2

私は以下のモデルを持っています

public class Order
{
    [Key]
    public virtual string OrderNo {get;set;}
    public virtual IList<OrderItem> Items {get;set;}
}

public class OrderItem
{
    [Key]
    public virtual string ItemNo {get; set;}
    public virtual string ParentItemNo {get;set;}
    public virtual string OrderNo {get;set;}

    public virtual OrderItem ParentItem {get;set;}
    public virtual IList<OrderItem> ChildItems {get;set;}
    public virtual IList<ItemProperty> ItemProperties {get;set;}
    public virtual Order Order {get;set;}
}

public class ItemProperty
{
    [Key]
    public virtual string PropertyNo {get; set;}
    public virtual string ParentPropertyNo {get;set;}
    public virtual string OrderItemNo {get;set;}

    public virtual ItemProperty ParentProperty {get;set;}
    public virtual IList<ItemProperty> ChildProperties {get;set;}
    public virtual OrderItem OrderItem {get;set;}
}

切断された領域で実行しています (Entity Framework コンテキストから切断されたサービスを使用)

  1. 注文を作成してデータベースに保存します

クライアント:

service.CreateOrder(new Order() { OrderN="fksjdf1" });

サーバ:

using(EfDbContext context = new EfDbContext())
{
    context.Orders.Add(order);
    context.SaveChanges();
}
  1. 以前に追加した注文に 1 つ以上の OrderItems を追加する必要があります

クライアント:

var order = service.GetOrder("fksjdf1");

var item1 = new OrderItem();
item1.ItemNo="i1";
item1.Order=order;
item1.OrderNo=order.OrderNo;
item1.ItemProperties.Add(new ItemProperty()
    PropertyNo="p1",
    OrderItem = item1
})
order.Items.Add(item1);

var item2 = new OrderItem();
item2.ItemNo="i2";
item2.Order=order;
item2.OrderNo=order.OrderNo;
item2.ItemProperties.Add(new ItemProperty()
    PropertyNo="p2",
    OrderItem = item2
});
item2.ItemProperties.Add(new ItemProperty()
    PropertyNo="p3",
    OrderItem = item2
})
order.Items.Add(item2);
service.UpdateOrder(order);

サーバ:

using(EfDbContext context = new EfDbContext())
{
    DbEntityEntry dbEntityEntry = context.Entry(order);
    if (dbEntityEntry.State == EntityState.Detached)
    {
        // ERROR
        context.Set<Order>().Attach(order);
    }

    dbEntityEntry.State = EntityState.Modified;
    context.SaveChanges();
}

エラー: 参照整合性制約違反が発生しました: 参照制約を定義するプロパティ値が、リレーションシップ内のプリンシパル オブジェクトと従属オブジェクトの間で一貫していません。

このエラーが表示されるのはなぜですか? このエンティティを更新しないのはなぜですか?

非接続領域からエンティティ フレームワークを使用するにはどうすればよいですか?

編集1:

public Order GetOrder(string orderNo)
{
using (EfDbContext context = new EfDbContext())
            {
                context.Configuration.ProxyCreationEnabled = false;
                var order = context.Orders
                    .Include(o => o.OrderItems
                                      .Select(z => z.ItemProperties
                                                       .Select(y => y.ChildProperties)))
                                                       .Where(o => o.OrderNo == orderNo)
                    .FirstOrDefault();
            }
}
4

1 に答える 1

2

次のように、を設定OrderItemNoしていないため、おそらくこのエラーが発生します。ItemProperty

var item1 = new OrderItem();
item1.ItemNo="i1";
item1.Order=order;
item1.OrderNo=order.OrderNo;
item1.ItemProperties.Add(new ItemProperty {
    PropertyNo="p1",
    OrderItem = item1,
    OrderItemNo = item1.ItemNo // = "i1"
});
order.Items.Add(item1);

// and the same for item2

注文がコンテキストに添付されると、関連する注文アイテムとアイテムのプロパティも添付されます。のナビゲーションプロパティOrderItemItemProperty、指定したキー()を持つエンティティを参照しています"i1"が、外部キーOrderItemNoにはこのキー値がありません。それは例外が不平を言っている矛盾です。

編集

残念ながら、データベース内のデタッチされたオブジェクトグラフを更新するのはそれほど簡単ではありません。エンティティの状態を、Modifiedこのエンティティを関連エンティティとしてのみマークしModified、関連エンティティとしてマークしないように設定します。

この方法GetOrderでは、既存のアイテムや関連するアイテムをクライアントに熱心にロードし、OrderItemクライアント側で新しいを追加して、この新しい変更されたオブジェクトグラフをサーバーに送り返すため、作業が複雑になります。サーバー側では、既存のアイテムを新しいアイテム(データベースに挿入)とは異なる方法で処理する(データベースに挿入しない)必要があるという問題があります。これを行うには、どのアイテムが古いか、どのアイテムが新しいかを検出する必要があります。エンティティ自体に、エンティティが新しいかどうかを示すフラグを転送しない場合は、データベースに再度クエリを実行し、DBからロードされたオブジェクトグラフをクライアントから送信されたデタッチされたオブジェクトグラフと比較する必要があります。それがどのように行われるかについての一般的なスケッチはここにあります:https://stackoverflow.com/a/5540956/270591(これは、子コレクションを持つ親の場合のみです。モデルのように孫コレクションが含まれる場合は、より複雑になります。)

service.UpdateOrder(order)私の意見では、オブジェクトグラフで可能なすべての変更を処理しようとするこのグローバルメソッドだけでなく、グラフの変更に関する知識を活用するいくつかの特殊なメソッド(この場合)があれば、手順全体を簡略化できます。OrderItem既存の注文に新しいを追加するための特殊な方法。次のようになります。

var order = service.GetOrder("fksjdf1");

var newOrderItems = new List<OrderItem>();

var item1 = new OrderItem();
item1.ItemNo="i1";
item1.OrderNo=order.OrderNo; // leave the Order property null
item1.ItemProperties.Add(new ItemProperty { PropertyNo="p1" });
newOrderItems.Add(item1);

// the same for item2
newOrderItems.Add(item2);

service.AddNewOrderItems(newOrderItems);

そして、サービス方法は次のようになります。

public void AddNewOrderItems(List<OrderItem> newOrderItems)
{
    using(EfDbContext context = new EfDbContext())
    {
        foreach (var newOrderItem in newOrderItems)
            context.Set<OrderItem>().Add(newOrderItem);

        context.SaveChanges();
    }
}
于 2012-10-19T15:43:17.443 に答える