为什么DbSet.Add会更改其他实体的属性?

时间:2015-07-28 08:33:39

标签: entity-framework ef-code-first entity-framework-6

我有一种罕见的情况,DbSet<T>.Add()的调用会更改DbSet<T>中已有的其他实体的某些属性。不幸的是,它很少发生,我唯一的证据是一些日志文件,所以我还没有能够在本地重现它。

行为是这样的:

  1. 首先,我们使用LINQ查询从DbSet加载一些实体。
  2. 然后,其中一些实体发生了变化。还没有SaveChanges()
  3. 现在我们通过调用DbSet<T>.Add()添加一些实体。
  4. 步骤2中的某些实体在步骤3中进行了更改(其中一个外键属性设置为null)。

    有什么想法吗?这是在EF 6 Code-First模型上可能发生的事情吗?

    我能想到的唯一可能性是DbContext刷新数据库中的一些数据,但我们现在不希望它这样做。

    编辑:代码目前分散在日志语句中,因为我们几周来一直在追逐这个bug。这些是相关的代码部分:

    // parameter: List<Entry> entriesFromUser
    
    var entriesFromDb = db.Entries
        .Where(...)
        .OrderBy(...)
        .ToList();
    
    var newEntries = MergeEntries(entriesFromDb, entriesFromUser);
    
    var propertyBefore = entriesFromDb[0].MyForeignKeyId;
    for (var i = 0; i < newEntries.Count; i++)
    {
        // make sure that the "new entry" is not a modified one
        if (entriesFromDb.Contains(newEntries[i])
        {
            throw new Exception();
        }
    
        db.Entries.Add(newEntries[i]);
    }
    
    var propertyAfter = entriesFromDb[0].MyForeignKeyId;
    
    Debug.Assert(propertyBefore == propertyAfter);          // <=== fails sometimes
    
    db.SaveChanges();
    

    请注意,已添加到DbSet的实体的更改外键为 NOT 。它来自数据库中的实体,但在同一事务中已更改。

1 个答案:

答案 0 :(得分:0)

D'哦。找到原因。希望它可以帮助别人。

我们正在使用Foreign Key Associations,这意味着我们同时拥有导航属性entry.MyForeignKey和外键属性entry.MyForeignKeyId,这有很多优点,但它也意味着你必须是有时使用时要小心,有时也要使用这个属性。

事实证明,我们在代码的某处深处进行了以下任务,其中一个条目的所有数据都被复制到另一个条目:

entry.MyForeignKeyId = otherEntry.MyForeignKeyId
entry.MyForeignKey = otherEntry.MyForeignKey

但是,在许多情况下,您将外键值设置为实体的MyForeignKeyId,但将属性MyForeignKey保留为null,因为未加载父实体。只要您没有将null 赋值给实体的MyForeignKey属性,这就没问题了,因为看起来EF似乎也会将MyForeignKeyId设置为null。

因此,似乎在我们的代码为MyForeignKey分配了null之后,实体在内存中以空MyForeignKey和非空MyForeignKeyId进行了徘徊。一旦执行了下一个DbSet命令(Add()操作),DbSet注意到MyForeignKey已收到null分配,因此{{1继续并将DbSet分配给null