在Entity Framework上预先加载导航属性

时间:2016-05-20 18:55:26

标签: c# asp.net entity-framework linq linq-to-entities

我一直在网上搜索我的问题的解决方案,但找不到任何有效的方法。

我有一个选择新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属性,以便在循环访问客户时不会多次访问数据库。我认为让include会急切加载导航属性。

我知道我可以在myDTO中放置一个订单属性并以这种方式加载它,但我很好奇是否可能采用上述方式。

谢谢!

2 个答案:

答案 0 :(得分:0)

我不确定您是否可以在仍启用延迟加载的情况下急切加载属性。如果您愿意仅针对Orders的{​​{1}}属性或整个上下文禁用延迟加载,那么它应该按您呈现的方式工作。

您可以通过从Customers属性中删除virtual关键字,或者通过添加以下内容为整个dbContext关闭它来执行此操作:

Orders

到你的dbContext构造函数。然后急切加载您呈现它的方式应该可以正常工作。

但是,请记住,您将来必须始终加载该属性(或所有导航属性,具体取决于您采用的方法)。

答案 1 :(得分:0)

正如您所知,急切加载(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已填充,因为当上下文包含相关实体(也称为 relationship fixup )时,EF会自动填充导航属性。必须禁用延迟加载,因为myDTO.Customer.Orders未在内部加载标记,因此解决它仍会触发延迟加载。