保存父实体时,新的子实体将不会保存
-
02-01-2020 - |
题
我有一个父实体
foo
存在于数据库中,我有一个属性 bar
在此实体上(一对多关系)。
Foo
已分离,因为它使用 WebApi 进行反序列化,所以我这样做是为了 foo
context.Foos.AddOrUpdate(foo);
就算有新的 bar
附加到它的引用,它不会被保存,但是对于我们拥有的另一个关系(多对多关系)来说,它确实像这样工作。如果我向该集合添加一个新实体,它将被保存到其表中,并且还会向关系表中添加一行。
如果我做 context.Bars.AddOrUpdate(foo.Bar);
打电话之前 context.Foos.AddOrUpdate(foo);
它会将新的 bar 正确保存到 bar 表中,但不会将正确的 barId 添加到 foo 表中
@尤利亚姆·钱德拉
如果我正确理解你的答案(我认为你在答案中混淆了 bar 和 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;
前面的答案解释了两个条件。
新 Foo 和现有 Bar
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
新Foo和新酒吧
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();
为了防止这种情况发生,需要先附加 Bar。
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.add方法(即ScreenCasts.Add)时,不仅是“添加”根实体的状态也添加了标记。即使开发人员可能意识到该主题具有现有的ID值,Entity Framework仍会尊重其实体state(添加)并为主题创建插入数据库命令,而不论现有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();
如果我们手动将 Bar 添加到 AddOrUpdate(foo)
, ,结果还是没有达到预期。将添加新的 Bar,但 Foo 将与新的 Bar 没有关系。
db.Bars.Add(foo.Bar);
db.Foos.AddOrUpdate(foo);
的行为 AddOrUpdate
不一致。
解决方案
如果您正在使用断开的对象,则必须手动管理同步。
该代码应该在所有条件下都有效。
- 新Foo和新酒吧
- 新Foo和现有酒吧
- 现有的 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
, ,我认为有一个未解决的问题可以找到 这里.