更改值适用于急切加载,但不适用于 linq 和 ef 中的延迟加载

发布于 2024-11-08 23:12:57 字数 965 浏览 0 评论 0原文

这不是“问题”问题,而是“为什么会发生这种情况”问题。

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();

我只想解释一下行为

this is not 'a problem' question , but 'why this happens' question.

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

first i want to get some data. story is an entity type of type Story and it has One To Many relation with Chapter i want to change some data in the chapters collection that i got so i write some condition if so change the value

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

and then i send the data to the view but the problem is :

nothing is changed due to lazy loading , the change that i made wasn't triggerd even after sending the data to the view , Why ? i made an assigment statment and shouldn't passing the data to the view trigger it ?

the solution was of course using ToList to execute the query immediately

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

i just want an explanation to the behavior

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

淡紫姑娘! 2024-11-15 23:12:57

因为您说您的 Story 类上有一个延迟加载的集合 Chapters,所以我假设 Chapters 实际上是动态代理对象的集合。如果您使用探查器查看数据库中发生的情况,您将看到这一行......

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

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

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,您可以在内存集合内的唯一对象上设置属性。当您在视图中使用此集合时,该标志仍​​然存在。

Because you say that you have a lazily loaded collection Chapters on your Story class I assume that Chapters is actually a collection of dynamic proxy objects. If you look what happens in the database with a profiler you will see that this line ...

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

... executes a query in the database which queries all Chapter objects (the projection into ChapterDisplayViewModel doesn't happen in the database). And that's the only database query. The following ...

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

... is executed in memory on the already lazily loaded collection of Chapters. The projection happens at this point.

But this means that the Single operator materializes a ChapterDisplayViewModel object, it means: There happens a new ChapterDisplayViewModel somewhere internally. Simple check for this:

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

bool sameObjects = object.ReferenceEquals(viewModel1, viewModel2);

sameObjects is false which means Single doesn't simply return references to ViewModel objects which are already in memory but creates new instances of them.

When you apply ToList in the first query the ViewModels are materialized at once into a in-memory collection of ViewModels and Single will simply return a reference to the matching, but already existing object. sameObjects will be true.

So, without ToList you are setting the IsSelected property on a just materialized object which you don't reference anymore and therefore disappears in garbage collection immediately. With ToList you are setting the property on the unique object inside of the in-memory collection. When you use this collection in your view the flag is still there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文