Eager, Lazy和显式加载在EF6中
Eager, Lazy和显式加载在EF6中
我阅读了这篇教程和这篇文章,但我不明白每种加载类型的具体用途。
我解释一下
我有这个 POCO:
public partial class dpc_gestion { public dpc_gestion() { this.ass_reunion_participant = new HashSet(); this.dpc_participant = new HashSet(); this.dpc_reunion = new HashSet(); } public int dpc_id_pk { get; set; } public Nullable dpc_id_gdp_fk { get; set; } public Nullable dpc_id_theme { get; set; } public int dpc_id_animateur_fk { get; set; } public Nullable dpc_date_creation { get; set; } public Nullable dpc_date_fin { get; set; } public Nullable dpc_date_engag_anim { get; set; } public Nullable dpc_flg_let_engag_anim { get; set; } public Nullable dpc_flg_fsoins_anim { get; set; } public virtual ICollection ass_reunion_participant { get; set; } public virtual theme_dpc theme_dpc { get; set; } public virtual gdp_groupe_de_pair gdp_groupe_de_pair { get; set; } public virtual ICollection dpc_participant { get; set; } public virtual ICollection dpc_reunion { get; set; } }
我理解了这个:
- 对于延迟加载:因为加载是延迟的,如果我调用 dbset
dpc_gestion
,所有导航属性将不会被加载。这种类型的加载在性能和响应速度方面是最好的。它默认启用,如果我想重新启用它,我必须设置:context.Configuration.ProxyCreationEnabled = true; context.Configuration.LazyLoadingEnabled = true;
- 对于及早加载:
它不是延迟加载:当我加载
dpc_gestion
时,它会加载所有导航属性。可以使用include
方法加载导航属性。要启用此加载类型:context.Configuration.LazyLoadingEnabled = false;
- 对于显式加载
它类似于急切加载,但是我们使用
Load
方法而不是include
。
所以我想知道:
- 这个简短的摘要是否正确?
- 如果是正确的,那么及早加载和显式加载有什么区别?
- 如果我使用延迟加载,例如我调用
dpc_gestion.dpc_participant
,导航属性是否会加载?或者我会得到异常吗? - 是否存在这样的情况,即及早加载或显式加载在性能和响应速度方面比延迟加载更好?
谢谢
问题1和2:
你对惰性加载和急切加载的解释是正确的。
显式加载的使用与你描述的有点不同。
EntityFramework
返回IQueryable
对象,这些对象本质上包含对数据库的查询。但是这些对象直到第一次枚举它们时才被执行。
Load
执行查询以便将其结果存储在本地。
调用Load
相当于调用ToList
并丢弃该List
,而没有创建List
的开销。
问题3:
如果使用惰性加载,EntityFramework
将负责为您加载导航属性,因此不会出现异常。
请记住,这可能需要一段时间并使您的应用程序无响应。
问题4:
在断开连接的情况下(例如网络应用程序),您无法使用惰性加载,因为这些对象被转换为DTO,然后无法被EntityFramework
跟踪。
此外,如果您知道将要使用导航属性,最好对其进行急切加载,这样就不必等到它们从数据库中加载。
例如,假设您将结果存储在列表中并将其绑定到WPF DataGrid。如果DataGrid访问尚未加载的属性,则用户会经历明显的超时,直到显示该属性。此外,如果您不异步加载,则应用程序将在加载期间不响应。
如果这份简历是真的?
是的。
如果是真的,那么急切加载和显式加载有什么区别?
急切加载是 懒惰加载 的相反,但显式加载类似于懒惰加载,唯一的不同是:您需要在代码中显式检索关联的数据;当您访问导航属性时,它不会自动发生。您可以通过获取实体的对象状态管理器条目,并为集合调用Collection.Load
方法或为保存单个实体的属性调用Reference.Load
方法来手动加载相关数据。
来自techblog:
急切加载:
急切加载是懒惰加载的相反,即以特定查询请求的对象为中心,加载一组相关对象。
显式加载:
当查询返回对象时,相关对象并不会同时加载。默认情况下,它们不会加载,直到使用导航属性上的Load方法显式请求。
并且:
如果我使用懒惰加载,例如调用
dpc_gestion.dpc_participant
,是否将导航属性加载?还是会出现异常?
您不会收到任何异常,导航属性应该会加载。
在性能和响应方面,急切加载或显式加载何时比懒惰加载更好?
急切加载通常对于需要检索主表的所有检索行的相关数据时更有效。当关系不太多时,急切加载是减少服务器上进一步查询的良好方法。但是当您知道您不会立即需要属性时,懒惰加载可能是一个不错的选择。并且,当处置您的数据库上下文后,急切加载是一个解决懒惰加载无法进行的情况的好选择。例如,考虑以下情况:
public ListGetAuctions() { using (DataContext db = new DataContext()) { return db.Auctions.ToList(); } }
调用此方法后,您无法懒惰加载相关实体,因为db
已被处置,因此在这里使用急切加载更好。
还有一件事要注意的是:懒惰加载将生成多个SQL请求,而急切加载将使用一个请求加载数据。这也是解决ORM中的n+1查询问题的一个好选择。
请查看此帖子:什么是关于n+1查询问题?