C#CodeFirst Lazy加载MVVM [英] C# CodeFirst Lazy Loading with MVVM

查看:174
本文介绍了C#CodeFirst Lazy加载MVVM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个适中的CodeFirst应用程序,它已经使用相当严格的MVVM(其中有一个C#/ WPF前端和CodeFirst到MS SQL Server后端)。



我已经在Model中编写了一些帮助类,它们创建了DbContext,加载对象等等。我曾经通过在每个线程(在静态函数中)生成一个单独的DbContext,并从适当的加载函数(Person.Load()将调用GetDbContext)获取该引用。由于每个线程使用这个单独的DbContext,所以我的代码中出现了一些错误,所以决定使用这个DbContext切换到每个工作单元的单个DbContext的更好的实践,在using语句中加载代码。现在似乎是微不足道的现实世界的速度差异。



我现在的问题是懒惰的加载。因为当访问Person的属性时,DbContext不再存在,automagic懒惰加载不会发生。



解决这个问题的最好方法是什么?当我访问这些属性之一时,我可以手动调用Model中的Model,但是我到处都是对Model的调用结束,并且手工执行应该在后台进行的事情。这也意味着事情似乎不那么协调 - 我结束了分离的POCO,似乎更糟糕的是,当我最初使用一个DbContext每个线程!数据库的归一化结构意味着有很多这样的关系。



另一个(非常耗资源的)方法可能是存储每个DbContext加载对象,以便延迟加载仍然有效...



提前感谢任何建议。
Adam

解决方案

一个静态 DBContext 一个很好的解决方案(特别是如果你有多个客户端访问数据库),所以重启你肯定是有道理的。



现在你有一个问题使用懒惰加载,因为一旦使用范围到达的结尾,则由于上下文已关闭其连接,因此无法再启动SQL请求 DB服务器已被处理



您正在谈论的解决方案


另一个(非常耗资源的)方法可能是将每个加载的对象存储一个 DBContext
,以便延迟加载仍然有效。 ..


其实是发生什么事情。允许延迟加载其导航属性之一的每个加载实体都与Entity Framework(即在运行时生成的类型的代理对象)相关,它继承自您的POCO),因此它实际上拥有参考 DBContext 已经。



这意味着,如果你不处理你的手动DBContext (使用使用),延迟加载仍然可用。这不是所有问题的解决方案,因为您可能会处理来自不同上下文的多个实体,这根本不会很容易(例如,您可以'将一个实体从 DBContext 实例A添加到 DBContext 实例B)。



现在,那么解决方案呢?那么这可能会很复杂。



您目前拥有2层应用程序,即您的重WPF客户端直接与数据库进行通信。启用Lazy加载,这意味着您的代码中的任何地方(特别是在ViewModels中),可以将SQL请求发送到DB服务器。这实际上远离工作模式的单位,更好地与无状态的3层应用程序配合使用。在这样的应用程序中,每次调用服务时,都会有一个新的工作单位,并实例化了一个新的实体上下文。



如果您正在启动新的应用程序,我会说:去一个3层无状态应用程序,尽可能缩短EF上下文生命周期,停用延迟加载,并在代码中的任何地方使用分离的实体。



现在,如果你已经有很多代码,你可能有两个选择:将所有这些想法重新整合到关于上下文生命周期的想法中,或者对你当前的代码进行细微的修改,以便只修复你现在使用的错误上下文每线程模式。


I have a moderate-sized CodeFirst application which has been written using fairly strict MVVM ( which has a C#/WPF front-end and CodeFirst to MS SQL Server backend).

I have written a load of helper classes in the Model, which create the DbContext, load objects and so on. I used to do this by generating a single DbContext per thread (in a static function) and obtaining that reference from the appropriate load function (Person.Load() would call GetDbContext). This worked quite nicely alongside lazy loading.

It got to a point where there were some bugs in my code due to the use of this single DbContext per thread and so decided to switch to the better practice of a single DbContext per work unit, with loading code inside a 'using' statement. There seems to be negligible real-world speed difference.

My problem now is one of lazy loading. Because when the properties on 'Person' are accessed, the DbContext no longer exists, 'automagic' lazy loading does not happen.

What's the best way to get around this? I can manually call the Model in my ViewModel when one of these properties is accessed, but I'm ending up with calls to the Model everywhere and doing things manually that should happen behind the scenes. It also means that things seem less coordinated - I'm ending up with detached POCO's and it seems more of a mess that when I was originally using one DbContext per thread! The normalized structure of the database does mean that there are lots of these sorts of relationships.

The other (very resource-hungry) method could be to store a DbContext with each loaded object so that lazy loading still works...

Thanks in advance for any advice. Adam

解决方案

One static DBContext is indeed generally not a good solution (especially if you have more than one client that accesses to the DB), so the refactoring you've started definitely makes sense.

Now you have a problem with lazy loading, because once you've reached the end of the using scope, you can't launch a SQL request anymore as the context has closed its connection to the DB server when it has been disposed.

The solution you're talking about

The other (very resource-hungry) method could be to store a DBContext with each loaded object so that lazy loading still works...

is actually what's happening under the hood. Each loaded entity that allows to lazy-load one of its navigation properties is related to Entity Framework (that's those proxy-object of a type generated at runtime that inherit from your POCOs), so it actually holds a reference to the DBContext already.

Which means, if you don't dispose your DBContext manually (with using), lazy-loading will still be available. This wouldn't be the solution to all your problems though, because you probably would have then to deal with multiple entities coming from different contexts, and this simply won't work easily (for example you can't add one entity coming from DBContext instance A into DBContext instance B).

Now, what's the solution then? Well, it probably will be complicated.

You currently have a 2-tiers application, i.e. your heavy WPF client directly communicates with the database. Lazy-loading is enabled, which means everywhere in your code (especially in the ViewModels), a SQL request could be sent to the DB server. This is actually far from the unit of work pattern that better works with a stateless 3-tier application. In such an application, each time you call a service you have a new "unit of work" and a new entity context instantiated.

If you were starting a new application, I would say: go for a 3-tier stateless application, shorten the EF context lifetime as much as possible, deactivate lazy-loading and work with detached entities everywhere in your code.

Now if you have already a lot of code, you probably have two options: either refactor it all with those ideas about context lifetime in mind, or make minor modifications to your current code to only fix the bugs you have right now with your context-per-thread pattern.

这篇关于C#CodeFirst Lazy加载MVVM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆