質問: 0) { context.Orders.Add(order); } context.SaveChanges(); } ``` そして本は言う: **Orderオブジェクトをデータベースに保存するとき。ユーザーのカートデータがセッションストアから逆シリアル化されると、JSONパッケージはEntity Framework Coreに認識されていない新しいオブジェクトを作成し、その後、すべてのオブジェクトをデータベースに書き込みます。 Productオブジェクトの場合、これは、Entity Framework Coreが既に格納されているオブジェクトを書き込もうとすることを意味し、エラーが発生します。この問題を回避するために、Entity Framework Coreにオブジェクトが存在することを通知し、変更しない限りデータベースに保存しないようにします** 私は混乱しており、2つの質問があります。 Q1-既に格納されているオブジェクトを書き込むとエラーが発生するのは、基礎となるデータベースの観点では、すべての列を現在の値に変更する更新SQLステートメントだけですか?すべてですが、データベースレベルでエラーをスローすべきではありませんか? Q2- `CartLine`に対して`CartLine`ようなことをしない理由: ``` context.AttachRange(order.Lines.Select(l => l.Product)); context.AttachRange(order.Lines); ``` `Product`オブジェクトに対して行うのと同じように、 `CartLine`オブジェクトがデータベースに保存されるのを防ぐには?
回答: さて、これは長いものになるでしょう: **最初の質問:** Entity Framework(コアまたは「古い」6)には、「変更追跡」という概念があります。 `DbContext`クラスは、データに対して行ったすべての変更を追跡し、SQLステートメント(INSERT、UPDATE、DELETE)を介してDBに適用します。ケースでエラーがスローされる理由を理解するには、 `DbContext` /変更追跡が実際にどのように`DbContext`するかを理解する必要があります。あなたの例を見てみましょう: ``` public void SaveOrder(Order order) { context.AttachRange(order.Lines.Select(l => l.Product)); if (order.OrderID == 0) { context.Orders.Add(order); } context.SaveChanges(); } ``` このメソッドでは、 `Lines`および`Products`を含む`Order`インスタンスを受け取ります。このメソッドが何らかのWebアプリケーションから呼び出されたと仮定しましょう**。つまり、DBからOrderエンティティをロードしなかった**ということです**。**これは、 孤立シナリオとして知られているものです `DbContext`がそれらの存在を認識していないという意味で、「切断」されています。 `context.AttachRange`実行すると、文字通りEFに`context.AttachRange`ます。 **私はここで管理し、これらのエンティティが既にDBに存在することを100%確信しています。今のところそれらに注意してください!** 、 コードをもう一度使用してみましょう。それが新しい`Order`あると想像し(もしあればそこに入力します)、コードの`context.AttachRange`部分を削除します。コードが`Add`および`SaveChanges`到達するとすぐに、これらのことは`DbContext`内部で発生し`DbContext` 。 1. `DetectChanges`メソッドが呼び出されます 2. 現在のグラフですべてのエンティティの`Order, Lines and Products`を検索しようとします 3. 見つからない場合、 **挿入される新しいレコード**として「保留中の変更」に追加**されます** その後、続行して`SaveChanges`を呼び出すと、ブックに`SaveChanges`ているように失敗します。どうして?選択された`Products`は次のとおりだと想像してください。 ``` Id: 1, "Macbook Pro" Id: 2, "Office Chair" ``` `DbContext`がエンティティを見て、それらのエンティティを知らなかった場合、 `DbContext`のエンティティを`Added`状態で保留中の変更に`Added` 。 `SaveChanges`を呼び出すと、モデル内の現在の状態に基づいて、これらの製品の`INSERT`ステートメントが発行されます。 Idの`1 and 2`はデータベースに既に存在するため、操作は失敗し、主キー違反が発生しました。 そのため、この場合は`Attach` (または`AttachRange` )を呼び出す必要があります。これは、エンティティがDBに存在することをEFに効果的に伝え、それらを再度挿入しようとするべきではありません。それらは`Unchanged`状態でコンテキストに追加されます。 `Attach`は、以前に`dbContext`からエンティティをロードしなかった場合によく使用されます。 **2番目の質問:** 私はそのレベルのコンテキスト/モデルを知らないので、これにアクセスするのは難しいですが、ここに私の推測があります: `Cartline`これを行う必要はありません。すべての注文で、おそらく新しい`Order line`を挿入する必要があるためです。アマゾンで物を買うように考えてください。商品をカートに入れると、 `Order` 、次に`Order Lines` 、その注文を構成するものが生成されます。 その後、既存の注文を更新してさらにアイテムを追加すると、同じ問題が発生します。 dbに保存する前に既存の`CartLines`をロードするか、ここで行ったように`Attach`を呼び出す必要があります。 それがもう少し明確であることを願っています。私はより多くの詳細を与えた同様の質問に答えたので、多分それを読むこともより役立つかもしれません: EF Core Modified Entity Stateはどう振る舞いますか?