在 LINQ 和 EF 中,更改值在急加载中有效,但在延迟加载中无效。

3

这不是'一个问题'的问题,而是'为什么会发生这样的问题'的问题。

var chapters = story.Chapters.Select(
                    ch => new ChapterDisplayViewModel { 
                                   Id = ch.Id,
                                   Number = ch.Number});

首先我想获取一些数据。故事是一个类型为Story的实体,它与Chapter有一对多的关系。我想改变我得到的章节集合中的一些数据,所以我编写了一些条件,如果满足条件,则改变值。

if(chapters.Any(c => c.Number == chapterNum))
   chapters.Where(c => c.Number == chapterNum).Single().IsSelected = true;

然后我将数据发送到视图,但问题是:

由于惰性加载,没有任何更改,即使在将数据发送到视图后也没有触发我所做的更改,为什么?我做了一个赋值语句,不应该将数据传递给视图触发它吗?

解决方案当然是使用ToList立即执行查询。

var chapters = story.Chapters.Select(
                    ch => new ChapterDisplayViewModel { 
                                   Id = ch.Id,
                                   Number = ch.Number}).ToList();

我只想解释这个行为。
1个回答

2

因为你说你在Story类上有一个懒加载的集合Chapters,我假设Chapters实际上是动态代理对象的集合。如果你使用分析器查看数据库中发生了什么,你会看到这一行代码...

var chapters = story.Chapters.Select(
               ch => new ChapterDisplayViewModel { 
                               Id = ch.Id,
                               Number = ch.Number});

...在数据库中执行一个查询,该查询查询所有Chapter对象(投影到ChapterDisplayViewModel不会在数据库中发生)。这就是唯一的数据库查询。接下来的...

if (chapters.Any(c => c.Number == chapterNum))
    chapters.Where(c => c.Number == chapterNum).Single().IsSelected = true;

这段代码在已经惰性加载的Chapters集合上,在内存中执行。此时进行投影。

但这意味着Single运算符会将ChapterDisplayViewModel对象具体化,也就是说:某个地方内部会发生new ChapterDisplayViewModel操作。可以简单检查一下:

var viewModel1 = chapters.Where(c => c.Number == chapterNum).Single();
var viewModel2 = chapters.Where(c => c.Number == chapterNum).Single();

bool sameObjects = object.ReferenceEquals(viewModel1, viewModel2);
sameObjectsfalse,这意味着Single不仅会返回已经在内存中的ViewModel对象的引用,而是创建它们的新实例。
当你在第一个查询中应用 ToList时,ViewModels会立即被实现为在内存中的ViewModels集合,并且Single将简单地返回对匹配但已存在的对象的引用。 sameObjects 将为 true
因此,如果没有使用ToList,则您正在设置IsSelected属性,但该对象已经被垃圾回收器删除了。而使用ToList,您正在设置内存中集合中唯一的对象上的属性。当您在视图中使用此集合时,标志仍然存在。

2
换句话说,它与惰性或急切加载无关。惰性加载仍然会发生。这只是延迟执行Linq查询的非常好的例子。很棒的解释。 - Ladislav Mrnka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接