【问题标题】:Foreign keys to different existing entities are not being saved on update of referencing entity更新引用实体时未保存不同现有实体的外键
【发布时间】:2011-11-11 19:54:24
【问题描述】:

我有一个 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 = ...

我做错了一些简单的事情,因为我以前也遇到过类似的情况。

【问题讨论】:

    标签: c# entity-framework ef-code-first foreign-key-relationship


    【解决方案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();
    

    如果您不想从数据库加载原始文件,则需要一些技巧编程:

    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 属性是标量的。

    【讨论】:

    • 我应该澄清A.B 在反序列化从客户端发送的A DTO 时设置为bb。因此,在使用differentdbcontext 之前,不会对A.B 进行真正的分配。是否有明确的方式告诉 EF 属性已更改而不进行分配?
    • @Kit:不,没有。明确告诉 EF 属性已更改仅支持标量和复杂属性,而不支持导航属性/关系。这是独立关联的弱点之一(= 没有外键属性),也是 EF 4 中引入 FK 关联(= 暴露外键)的主要原因。
    • 不知道能不能简化成一些辅助方法AttachIfNotAttached(Entity e)
    • @Vitalik - 我有这样一个方法,我将它用作通用存储库实现的一部分。我所有实施它的尝试都没有奏效。看来我需要一种通用的方法来完成之后的任务。
    猜你喜欢
    • 2015-12-20
    • 2013-05-09
    • 2013-04-03
    • 2018-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-26
    相关资源
    最近更新 更多