简体   繁体   English

实体框架:递归更新Parent-Child给我重复

[英]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不可见,但它在那里,只是没有刷新......):

D B

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(...)来检索旧键。
  • Why do I have a duplicate customer/locations in my context after adding a second child location? 添加第二个子位置后,为什么我的上下文中有重复的客户/位置? I end up with 5 locations and 2 customers instead of 3 locations and 1 customer, so it gives me a PK exception. 我最终得到5个地点和2个客户,而不是3个地点和1个客户,所以它给了我一个PK例外。 Somehow it creates a new customer after adding a child to a location. 不知何故,在将孩子添加到某个位置后,它会创建一个新客户。 So it has a customer entity with 2 locations, and one with 3 locations. 因此它有一个拥有2个位置的客户实体,以及一个拥有3个位置的实体。 Why??? 为什么???

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.

相关问题 实体框架自参考-父子 - Entity Framework self referencing - Parent-Child 使用实体框架或实体框架核心删除父子关系 - Deleting parent-child relation with Entity Framework or Entity Framework Core 如何在 Entity Framework Core 2.2 中使用预先加载策略实现自递归父子关系数据加载? - How to implement self-recursive parent-child relationship data loading with eager loading policy in Entity Framework Core 2.2? ASP.NET MVC 父子视图模型和实体框架 - ASP.NET MVC Parent-Child with ViewModel and Entity Framework 如何使用实体框架保持父子C#关系 - How to hold Parent-Child C# relationship with Entity Framework 在实体框架中删除父子表中的行 - remove row in parent-child table in Entity framework 递归父子关系 C# - Recursive Parent-Child Relationship C# 实体核心中的一对多关系删除子表中的先前记录作为父子更新的一部分 - One to many relationship in Entity core deleting the previous records in child table as part of parent-child update 实体更新后,实体框架仍然为我提供了旧信息吗? - after entity update entity framework still gives me old info? 实体框架:如何在自引用父子关系上指定外键列的名称? - Entity Framework: How to specify the name of Foreign Key column on a self-referencing Parent-Child relationship?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM