我有一个引用A
实体的POCO B
实体,让我们说b
。我希望A
引用不同的现有B
实体,让我们说bb
。
这些步骤:
var b = // get existing b from somewhere out-of-context
var a = new A { B = b }
dbcontext.Set<B>.Attach(a.B);
dbcontext.Set<A>.Add(a);
context.SaveChanges();
按预期生成a
的插入语句,并将B_ID
外键正确设置为主键ID b
。这些后续步骤:
var bb = // get existing bb from somewhere out-of-context
a.B = bb;
differentdbcontext.Set<B>.Attach(a.B);
differentdbcontext.Set<A>.Attach(a);
differentdbcontext.Entry(a).State = EntityState.Modified;
differentdbcontext.SaveChanges();
导致持久数据无变化。更新语句未按预期包含 set B_ID = ...
。
我正在做一些简单的错误,因为我之前还有其他类似的工作方式。
答案 0 :(得分:1)
将状态设置为Modified
仅对标量属性有影响,但对导航属性没有影响。我假设B_ID
不是模型中的属性,只是数据库中的外键列没有暴露给您的模型。
在这种情况下,您只能通过利用Entity Framework的自动更改检测来更新关系。一种方法 - 我称之为标准方法 - 是从数据库加载原始A
包括原始B
,将a.B
设置为新的bb
然后保存更改:
var bb = // get existing bb from somewhere out-of-context
differentdbcontext.Set<B>().Attach(bb);
differentdbcontext.Set<A>().Include(x => x.B).Single(x => x.Id == a.Id);
a.B = bb;
differentdbcontext.SaveChanges();
如果您不想从DB加载原始文件,则需要进行一些技巧编程:
var bb = // get existing bb from somewhere out-of-context
if ( (a.B == null && bb != null)
|| (a.B != null && bb == null)
|| (a.B != null && bb != null && a.B.Id != bb.Id)) //take care not to attach
//two objects with same key
{
if (bb != null)
differentdbcontext.Set<B>().Attach(bb);
differentdbcontext.Set<A>().Attach(a);
a.B = bb; // EF will detect this change
}
else if (a.B == null && bb == null)
{
// create a dummy a.B
a.B = new B(); // it doesn't matter which Id
differentdbcontext.Set<A>().Attach(a);
a.B = bb; // = null -> EF will detect a change
}
differentdbcontext.SaveChanges();
或类似的。我们的想法是在附加对象后更改引用,以便更改检测将FK列的更新发送到数据库。
将外键作为属性公开到模型中会使这种情况变得更加容易。将状态设置为Modified
将起作用,因为FK属性是标量。