0

次の表があるとします(スクリーンショットでは、場所から顧客へのFKは表示されていませんが、そこにあり、更新されませんでした...):

DB

そして私のマッピング:

    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(...)を使用して古いキーを取得できません。
  • 2番目の子の場所を追加した後、コンテキストに重複する顧客/場所があるのはなぜですか?最終的に、3つの場所と1つの顧客ではなく、5つの場所と2つの顧客になるため、PK例外が発生します。どういうわけか、場所に子供を追加した後、新しい顧客を作成します。つまり、2つの場所を持つ顧客エンティティと3つの場所を持つ1つの顧客エンティティがあります。なぜ???
4

1 に答える 1

2

製品を更新するにはどうすればよいですか? キーの一部を変更したため、 context.Entry(...) を使用して古いキーを取得できません。

Entity Framework でエンティティのキ​​ーを変更または更新することはできません。これを行う必要がある場合は、手書きの SQL コマンドを使用する必要があります。

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

2 番目の子ロケーションを追加した後、コンテキスト内に顧客/ロケーションが重複するのはなぜですか?

分離オブジェクト グラフを に渡しますUpdateLocations。グラフのいずれかのノードをコンテキストに追加すると、そのノードからのナビゲーション プロパティによって到達可能な他のすべての切り離されたエンティティがコンテキストに追加され、それらはすべて EntityState を持ちますAdded。呼び出すとSaveChanges、エンティティがデータベースに挿入されます。これは、たとえば次のように発生します。

context.Locations.Add(location);

新しい場所には顧客への参照があるため、顧客Addedも同様に状態になり、データベース内で顧客が複製されます。これは、最初に顧客をコンテキストに関連付けることで回避できます。呼び出しAttachにより、エンティティが状態Unchangedになり、顧客の重複が回避されます。

context.Customers.Attach(location.Customer);
context.Locations.Add(location);
于 2012-08-23T14:48:18.643 に答える