我有一个非常基本的示例C#程序,该程序将EF6与DbContext一起使用,并且包含两个类:
MyTable1 1...n MyTable2
我有以下代码:
// Creation of instances and saving them to the database.
using (var context = new EFTestEntities()) {
var myTable1 = new MyTable1() { ID = 1 };
var myTable2 = new MyTable2() { ID = 2 };
myTable1.MyTable2.Add(myTable2);
context.MyTable1.Add(myTable1);
context.SaveChanges();
}
// This part here is what my question is about.
using (var context = new EFTestEntities()) {
var myTable2 = context.MyTable2.Where(e => e.ID == 2).FirstOrDefault(); // First line
myTable2.MyTable1 = null; // Second line
var myTable1AssignedToMyTable2 = myTable2.MyTable1.ID; // Value '1'; third line
}
代码的第二部分是我的问题所在。
myTable1AssignedToMyTable2
的值为'1'。我希望有一个NullReferenceException
。
启动SQL Server Profiler以查看所有数据库访问时,我意识到myTable2的MyTable1导航属性是由于第一次访问时自动加载的延迟加载而引起的。这发生在第三行或在调试会话的第二行中悬停单词MyTable1
时。
延迟加载之后,可以将其设置为null。
但是:如果我将上面的空分配替换为:
myTable2.MyTable1 = new MyTable1() { ID = 11 };
然后myTable1AssignedToMyTable2
的期望值为'11'。而且不会再进行数据库访问。
进一步观察:
如果我先分配一个新值并分配,然后再分配旧值,它仍然会被忽略。仅当我在两者之间调用DetectChanges()
时,才符合预期。示例:
using (var context = new EFTestEntities()) {
var myTable2 = context.MyTable2.Where(e => e.ID == 2).FirstOrDefault();
myTable2.MyTable1 = new MyTable1() { ID = 11 };
// context.ChangeTracker.DetectChanges();
myTable2.MyTable1 = null;
var myTable1AssignedToMyTable2 = myTable2.MyTable1.ID; // Value is still '1'
}
结论:
EF似乎忽略了再次分配当前值。进一步的测试表明,是否为null
都没关系。
有时EF需要DetectChanges()
才能意识到某些更改,有时没有更改。用一个新的对象(参见上文,在本文的中间)用一个赋值替换空赋值就不需要调用DetectChanges()
。但是,再次执行此操作并将其重新设置为null,则需要进行DetectChanges()
调用(请参见上面的示例)。
这是正确的吗?我认为这不是很直观。分配空值将被忽略,分配非空值将不会被忽略。