我有一种罕见的情况,DbSet<T>.Add()
的调用会更改DbSet<T>
中已有的其他实体的某些属性。不幸的是,它很少发生,我唯一的证据是一些日志文件,所以我还没有能够在本地重现它。
行为是这样的:
DbSet
加载一些实体。SaveChanges()
。DbSet<T>.Add()
添加一些实体。步骤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 。它来自数据库中的实体,但在同一事务中已更改。
答案 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
。