DbContext:向导航属性分配null时的延迟加载

时间:2019-08-22 08:03:37

标签: c# entity-framework-6 lazy-loading dbcontext

我有一个非常基本的示例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()调用(请参见上面的示例)。

这是正确的吗?我认为这不是很直观。分配空值将被忽略,分配非空值将不会被忽略。

0 个答案:

没有答案