親エンティティが保存されているときに新しいサブエンティティは保存されません
-
02-01-2020 - |
質問
私は親エンティティを持っています
foo
dbに存在する、私はプロパティを持っています bar
このエンティティ(1対多の関係)。
Foo
WebApiを使用して逆シリアル化されているため、切り離されているため、これを次のようにします foo
context.Foos.AddOrUpdate(foo);
新しいものがあっても bar
参照が添付されていると、保存されませんが、多対多の関係である別の関係ではこのように機能します。そのコレクションに新しいエンティティを追加すると、そのテーブルに保存され、関係テーブルにも行が追加されます。
私がしたら context.Bars.AddOrUpdate(foo.Bar);
呼び出す前に context.Foos.AddOrUpdate(foo);
新しいバーをbarテーブルに正しく保存しますが、正しいbarIdをfooテーブルに追加しません
@Yuliam Chandra
私があなたの答えを正しく理解していれば(私はあなたがあなたの答えにbarsとfoosを混ぜていると思います)、これはうまくいくはずですか?
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
しかし、それはしません
解決
切断されたオブジェクトを操作するには、余分なコードが必要です。
切断されたオブジェクトを操作している場合は、手動で管理する必要があります 同期しています。
もし Bar
最初に添付する必要がある既存のエンティティなので、 Foo
として追加されます Bar's
子供たち。
if (foo.Bar.Id != 0)
{
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
}
上記のコードの例は次のようになります Course
(Foo
)と Department
(Bar
)での例 この記事.
しかし、もし Bar
あなたが追加する必要がある新しいエンティティですか Foo
, 、その後 Bar
また、追加されます。
else
{
context.Foos.Add(foo);
}
他のいくつかの品種をチェックすることができます 私の答え.
更新
さらに説明する前に、同じコードを表示したいと思います。
db.Set<T>().Add(instance)
に等しいdb.Entry(instance).State = EntityState.Added;
db.Set<T>().Attach(instance)
に等しいdb.Entry(instance).State = EntityState.Unchanged;
前の答えは2つの条件について説明しました。
新しいFooと既存のBar
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
新しいFooと新しいBar
context.Foos.Add(foo);
特別追加
Added
エンティティが次のようにマークされると、特別な条件があります Added
.グラフ内のすべてのエンティティは次のようにマークされます Added
また、参照エンティティがデータベース内の既存のオブジェクトであっても。このコードがあれば、FooとBarが追加されます。
var foo = new Foo (); // new foo
foo.Bar = new Bar { BarId = 123 }; // existing bar
db.Set<Foo>().Add(foo);
db.SaveChanges();
それが起こらないようにするには、最初にバーを取り付ける必要があります。
var foo = new Foo (); // new foo
foo.Bar = new Bar { BarId = 123 }; // existing bar
db.Set<Bar>().Attach(bar);
db.Set<Foo>().Add(foo);
db.SaveChanges();
チェック ジュリー-ラーマンの記事 より完全な説明のために。
それが起こる理由は、DbSetを使用するときです。メソッドを追加( は、スクリーンキャストです。追加)、ルートエンティティの状態がマークされているだけでなく "追加された"しかし、コンテキストがなかったことをグラフ内のすべて 以前の認識も同様に追加されたマークされています。開発者にもかかわらず トピックに既存のId値Entity Frameworkがあることを認識している可能性があります そのEntityState(追加)を尊重し、Insert databaseコマンドを作成します 既存のIdに関係なく、トピックの場合。
更新に基づいて説明を調整する
そして、あなたの更新された質問は、既存のFooと新しいBarに関するものです。コードを使用すると、結果は新しいBarを追加せず、既存のFooは新しいBarとの関係を作成しません。
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
と一緒にバーを手動で追加した場合 AddOrUpdate(foo)
, 、結果はまだ期待どおりではありません。新しいバーが追加されますが、Fooは新しいバーとの関係を持ちません。
db.Bars.Add(foo.Bar);
db.Foos.AddOrUpdate(foo);
の動作 AddOrUpdate
一貫性がありません。
ソリューション
切断されたオブジェクトを操作している場合は、手動で管理する必要があります 同期しています。
このコードはすべての条件で動作するはずです。
- 新しいFooと新しいBar
- 新しいFooと既存のBar
- 既存のFooと新しいBar
- 既存のFooと既存のBar
このコードはidに依存します(id=0は新しいエンティティです)。
db.Entry(foo).State =
foo.FooId == 0 ? EntityState.Added : EntityState.Modified;
if (foo.Bar != null)
{
db.Entry(foo.Bar).State =
foo.Bar.BarId == 0 ? EntityState.Added : EntityState.Modified;
^^^
// If you don't want to change the Bar while creating a relationship between
// Foo and with existing Bar, you can change
// `EntityState.Modified` with `EntityState.Unchanged`
}
db.SaveChanges();
に関連する AddOrUpdate
, 、私は見つけることができる未解決の問題があると思います ここに.