gpt4 book ai didi

c# - 更改值适用于预加载但不适用于 linq 和 ef 中的惰性加载

转载 作者:行者123 更新时间:2023-11-30 17:17:56 25 4
gpt4 key购买 nike

这不是“问题”的问题,而是“为什么会这样”的问题。

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

首先我想获取一些数据。 story 是 Story 类型的实体类型,它与 Chapter 具有一对多关系我想更改我得到的章节集合中的一些数据所以我写了一些条件如果所以改变值(value)

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

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

由于延迟加载,没有任何改变,即使在将数据发送到 View 后我所做的改变也没有被触发,为什么?我做了一个分配声明,不应该将数据传递给 View 触发它吗?

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

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

我只是想解释一下这个行为

最佳答案

因为你说你的 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 时,ViewModel 会立即具体化到内存中的 ViewModel 集合中,Single 将简单地返回对匹配项的引用,但已经存在的对象。 sameObjects 将为 true

因此,如果没有 ToList,您将在一个刚刚物化的对象上设置 IsSelected 属性,您不再引用该对象,因此会立即在垃圾回收中消失。使用 ToList,您可以在内存集合中的唯一对象上设置属性。当您在 View 中使用此集合时,该标志仍​​然存在。

关于c# - 更改值适用于预加载但不适用于 linq 和 ef 中的惰性加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6078399/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com