在更新引用实体时不保存不同现有实体的外键

本文关键字:实体 保存 更新 引用 | 更新日期: 2023-09-27 18:14:34

我有一个POCO A实体引用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外键正确设置为b的主键ID。下面的步骤:

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 = ...

我正在做一些简单的错误,因为我以前有过类似的工作场景

在更新引用实体时不保存不同现有实体的外键

将状态设置为Modified只对标量属性有影响,但对导航属性没有影响。我假设B_ID不是你的模型中的属性,而只是数据库中的外键列,不暴露给你的模型。

在这种情况下,您只能通过利用实体框架的自动变更检测来更新关系。一种方法——我称之为标准方法——是从数据库中加载原始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属性是标量。