[英]Entity framework : Recursive update Parent-Child gives me duplicates
Given the following tables (in screenshot FK from Locations to Customers is not visible, but it's there, just didn't refresh...): 鉴于以下表格(在屏幕截图中,从位置到客户的FK不可见,但它在那里,只是没有刷新......):
And my mapping: 我的映射:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>().ToTable("CUSTOMERS");
modelBuilder.Entity<Customer>().HasKey(c => c.Id).Property(c => c.Id).HasColumnName("CUSTNO");
modelBuilder.Entity<Customer>().Property(c => c.Name).HasColumnName("NAME");
modelBuilder.Entity<Customer>().HasMany(c => c.AllLocations).WithRequired(l => l.Customer).Map(x => x.MapKey("CUSTNO"));
modelBuilder.Entity<Customer>().Ignore(c => c.RootLocations);
modelBuilder.Entity<Location>().ToTable("LOCATIONS");
modelBuilder.Entity<Location>().HasKey(c => c.Id);
modelBuilder.Entity<Location>().Property(c => c.Id).HasColumnName("ID");
modelBuilder.Entity<Location>().Property(c => c.LocationCode).HasColumnName("LOCATION_CODE");
modelBuilder.Entity<Location>().HasMany(l => l.Children).WithOptional(ch => ch.Parent).Map(x => x.MapKey("PARENT_ID"));
modelBuilder.Entity<Product>().ToTable("PRODUCTS");
modelBuilder.Entity<Product>().HasKey(p => new { p.Partno, p.LocationId, p.Quantity, p.SellUnit });
modelBuilder.Entity<Product>().Property(p => p.Partno).HasColumnName("PARTNO");
modelBuilder.Entity<Product>().Property(p => p.LocationId).HasColumnName("LOCATION_ID");
modelBuilder.Entity<Product>().Property(p => p.PartDescription).HasColumnName("PART_DESCRIPTION");
modelBuilder.Entity<Product>().Property(p => p.Quantity).HasColumnName("QUANTITY");
modelBuilder.Entity<Product>().Property(p => p.SellUnit).HasColumnName("SELL_UNIT");
modelBuilder.Entity<Product>().HasRequired(p => p.Location).WithMany(l => l.Products).HasForeignKey(p => p.LocationId);
}
And my update code: 我的更新代码:
public void UpdateLocations(string customerId, IEnumerable<Location> locations)
{
using (var context = new CustomerWarehouseContext(connectionString))
{
foreach (var location in locations)
RecursiveUpdate(location, context);
context.SaveChanges();
}
}
private void RecursiveUpdate(Location location, CustomerWarehouseContext context)
{
if (location != null)
{
bool locationIsNew = location.Id.Equals(Guid.Empty);
if (locationIsNew)
{
location.Id = Guid.NewGuid();
context.Locations.Add(location);
}
else
{
context.Entry(context.Locations.Single(l => l.Id.Equals(location.Id))).CurrentValues.SetValues(location);
}
if (location.Children != null)
{
foreach (var childLocation in location.Children)
{
childLocation.Parent = location;
RecursiveUpdate(childLocation, context);
}
}
if (location.Products != null)
{
foreach (var product in location.Products)
{
if (locationIsNew)
{
location.Products.Add(product);
}
else
{
//How to update product when key is changed? I cannot use contex.Entry here?
}
}
}
}
}
I execute the following code: 我执行以下代码:
Customer customer = null;
using (var context = new AwesomeContext("myAwesomeConnectionString"))
{
customer = (from c in context.Customers.Include(c => c.AllLocations.Select(l => l.Products))
where c.Id.Equals("100100")
select c).FirstOrDefault();
}
Location locationToUpdate = customer.RootLocations.Single(l => l.Id.Equals(Guid.Parse("1a2ad52e-84cc-bf4c-b14d-dc57b6d229a6")));
locationToUpdate.LocationCode = "Parent " + DateTime.Now.Millisecond; //Goes OK
locationToUpdate.Children[0].LocationCode = "Child " + DateTime.Now.Millisecond; //Goes OK
locationToUpdate.Children[0].Products[0].Quantity = 200;
locationToUpdate.Children.Add(new Location() { LocationCode = "XXX", Customer = customer, Parent = locationToUpdate }); //Creates duplicates?
UpdateLocations(customer.Id, newList);
So, I'm changing the Location code of the parent and a child, update the product quantity of a product in the child location. 因此,我正在更改父级和子级的位置代码,更新子级位置中产品的产品数量。 Quantity is part of the key of the product table. 数量是产品表密钥的一部分。 Also, I'm adding a new location to the parent. 此外,我正在向父母添加新位置。
Questions: 问题:
How can I update my product? 我该如何更新我的产品? Because I changed part of the key, I cannot use context.Entry(...) to retrieve the old one. 因为我改变了部分键,所以我不能使用context.Entry(...)来检索旧键。
You cannot change or update the key of an entity with Entity Framework. 您无法使用Entity Framework更改或更新实体的密钥。 If you need to do this you must use a handwritten SQL command: 如果需要这样做,则必须使用手写SQL命令:
context.Database.ExecuteSqlCommand("UPDATE...");
Why do I have a duplicate customer/locations in my context after adding a second child location? 添加第二个子位置后,为什么我的上下文中有重复的客户/位置?
You pass in a detached object graph into your UpdateLocations
. 您将分离的对象图传递到UpdateLocations
。 If you add any node of the graph to the context all other detached entities that are reachable by navigation properties from that node will be added to the context and they all have EntityState Added
. 如果将图形的任何节点添加到上下文中,则该节点的导航属性可访问的所有其他分离实体将添加到上下文中,并且它们都已Added
EntityState。 If you call SaveChanges
the entities will be inserted into the database. 如果调用SaveChanges
,实体将插入到数据库中。 This happens here for example: 这发生在这里例如:
context.Locations.Add(location);
Because your new location has a reference to the customer the customer will be put into Added
state as well and this will duplicate the customer in the database. 因为您的新位置具有对客户的引用,所以客户也将被置于已Added
状态,这将在数据库中复制客户。 You can avoid this by attaching the customer first to the context. 您可以通过将客户首先附加到上下文来避免这种情况。 Calling Attach
will put the entity into state Unchanged
and avoid the duplication of the customer: 调用Attach
将实体置于Unchanged
状态并避免客户重复:
context.Customers.Attach(location.Customer);
context.Locations.Add(location);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.