实体框架上的急切加载导航属性
Posted
技术标签:
【中文标题】实体框架上的急切加载导航属性【英文标题】:Eager load navigation properties on Entity Framework 【发布时间】:2016-05-20 18:55:26 【问题描述】:我一直在互联网上寻找解决问题的方法,但还没有找到任何可行的方法。
我有一个像这样选择新 DTO 的查询:
List<myDTO> query = (from c in db.Customers
.Include(x => x.Orders)
where customerId = 5
select new myDTO
Customer = c,
...
).ToListAsync();
foreach (var custDto in query)
//this is lazy loaded
var customerOrder = custDto.Customers.Orders;
我的问题是当我尝试导航到 query.Customers.Orders 时,它是延迟加载的。我想急切地加载 Orders 属性,这样它在循环访问客户时不会多次访问数据库。我认为包含会急切加载导航属性。
我知道我可以在 myDTO 中放置一个 order 属性并以这种方式加载它,但我很好奇是否可以采用上述方式。
谢谢!
【问题讨论】:
【参考方案1】:我不确定您是否可以在仍然启用延迟加载的情况下预先加载属性。如果您愿意为 Customers
的 Orders
属性或整个上下文禁用延迟加载,那么它应该按照您呈现的方式工作。
您可以通过从 Orders
属性中删除 virtual
关键字或通过添加以下内容为整个 dbContext 关闭它来做到这一点:
this.Configuration.LazyLoadingEnabled = false;
到您的 dbContext 构造函数。然后以您呈现的方式急切加载它应该可以正常工作。
但是,请记住,您将来总是需要预先加载该属性(或所有导航属性,具体取决于您采用的方法)。
【讨论】:
【参考方案2】:正如您所发现的,急切加载 (Include
) 不起作用 when the query result is a projection。有时这很麻烦,在像你这样的情况下,当结果包含个完整实体时,我真的不明白为什么这些实体没有启用导航属性Include
ed。
无论如何,这是您必须找到解决方法的限制。正如你所说,包括Orders = c.Orders
这样的属性是可能的。你可以做的另一件事是
db.Configuration.LazyLoadingEnabled = false;
var intermed = (from c in db.Customers
where customerId = 5
select new
Customer = c,
...
Orders = c.Orders
).ToListAsync();
var dtos = intermed.Select(x => new myDTO
Customer = x.Customer,
...
).ToList();
您会注意到myDTO.Customer.Orders
已填充,因为当上下文包含相关实体时,EF 会自动填充导航属性(也称为关系修复)。必须禁用延迟加载,因为myDTO.Customer.Orders
没有标记为内部加载,因此解决它仍会触发延迟加载。
【讨论】:
以上是关于实体框架上的急切加载导航属性的主要内容,如果未能解决你的问题,请参考以下文章
我正在尝试使用实体框架进行急切加载,其中我在区域和客户端之间具有一对多的关系