簡體   English   中英

實體框架:遞歸更新Parent-Child給我重復

[英]Entity framework : Recursive update Parent-Child gives me duplicates

鑒於以下表格(在屏幕截圖中,從位置到客戶的FK不可見,但它在那里,只是沒有刷新......):

D B

我的映射:

    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);
    }

我的更新代碼:

    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?
                    }
                }
            }
        }
    }

我執行以下代碼:

        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);

因此,我正在更改父級和子級的位置代碼,更新子級位置中產品的產品數量。 數量是產品表密鑰的一部分。 此外,我正在向父母添加新位置。

問題:

  • 我該如何更新我的產品? 因為我改變了部分鍵,所以我不能使用context.Entry(...)來檢索舊鍵。
  • 添加第二個子位置后,為什么我的上下文中有重復的客戶/位置? 我最終得到5個地點和2個客戶,而不是3個地點和1個客戶,所以它給了我一個PK例外。 不知何故,在將孩子添加到某個位置后,它會創建一個新客戶。 因此它有一個擁有2個位置的客戶實體,以及一個擁有3個位置的實體。 為什么???

我該如何更新我的產品? 因為我改變了部分鍵,所以我不能使用context.Entry(...)來檢索舊鍵。

您無法使用Entity Framework更改或更新實體的密鑰。 如果需要這樣做,則必須使用手寫SQL命令:

context.Database.ExecuteSqlCommand("UPDATE...");

添加第二個子位置后,為什么我的上下文中有重復的客戶/位置?

您將分離的對象圖傳遞到UpdateLocations 如果將圖形的任何節點添加到上下文中,則該節點的導航屬性可訪問的所有其他分離實體將添加到上下文中,並且它們都已Added EntityState。 如果調用SaveChanges ,實體將插入到數據庫中。 這發生在這里例如:

context.Locations.Add(location);

因為您的新位置具有對客戶的引用,所以客戶也將被置於已Added狀態,這將在數據庫中復制客戶。 您可以通過將客戶首先附加到上下文來避免這種情況。 調用Attach將實體置於Unchanged狀態並避免客戶重復:

context.Customers.Attach(location.Customer);
context.Locations.Add(location);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM