Nat*_*Liu 167 linq entity-framework lazy-loading
这可能是一个非常重要的问题,但是当编写跨越三个级别(或更多)的查询时,包含多个子实体的好方法是什么?
即我有4个表:Company,Employee,Employee_Car和Employee_Country
公司与员工有1:m的关系.
Employee与Employee_Car和Employee_Country都有1:m的关系.
如果我想编写一个返回所有4个表中数据的查询,我目前正在编写:
Company company = context.Companies
.Include("Employee.Employee_Car")
.Include("Employee.Employee_Country")
.FirstOrDefault(c => c.Id == companyID);
Run Code Online (Sandbox Code Playgroud)
必须有一个更优雅的方式!这是冗长的,并产生可怕的SQL
我在VS 2010中使用EF4
Nix*_*Nix 192
使用扩展方法.将NameOfContext替换为对象上下文的名称.
public static class Extensions{
public static IQueryable<Company> CompleteCompanies(this NameOfContext context){
return context.Companies
.Include("Employee.Employee_Car")
.Include("Employee.Employee_Country") ;
}
public static Company CompanyById(this NameOfContext context, int companyID){
return context.Companies
.Include("Employee.Employee_Car")
.Include("Employee.Employee_Country")
.FirstOrDefault(c => c.Id == companyID) ;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你的代码变成了
Company company =
context.CompleteCompanies().FirstOrDefault(c => c.Id == companyID);
//or if you want even more
Company company =
context.CompanyById(companyID);
Run Code Online (Sandbox Code Playgroud)
Stu*_*tLC 147
EF 4.1至EF 6
有一个强类型.Include,它允许通过将Select表达式提供到适当的深度来指定所需的预先加载深度:
using System.Data.Entity; // NB!
var company = context.Companies
.Include(co => co.Employees.Select(emp => emp.Employee_Car))
.Include(co => co.Employees.Select(emp => emp.Employee_Country))
.FirstOrDefault(co => co.companyID == companyID);
Run Code Online (Sandbox Code Playgroud)
在这两个实例中生成的Sql仍然不是直观的,但看起来足够高效.我在这里给GitHub写了一个小例子
EF核心
EF Core有一个新的扩展方法.ThenInclude(),虽然语法略有不同:
var company = context.Companies
.Include(co => co.Employees)
.ThenInclude(emp => emp.Employee_Car)
...
Run Code Online (Sandbox Code Playgroud)
根据文档,我会保留额外的"缩进" .ThenInclude以保持你的理智.
过时的信息(不要这样做):
多个孙子加载可以在一个步骤中完成,但这需要在向下移动下一个节点之前备份相当笨拙的反转(NB:这不起作用AsNoTracking()- 您将得到运行时错误):
var company = context.Companies
.Include(co =>
co.Employees
.Select(emp => emp.Employee_Car
.Select(ec => ec.Employee)
.Select(emp2 => emp2.Employee_Country)))
.FirstOrDefault(co => co.companyID == companyID);
Run Code Online (Sandbox Code Playgroud)
所以我会继续使用第一个选项(每个实体深度模型包含一个).
Mer*_*ijn 27
您可能会在codeplex.com上找到这篇感兴趣的文章.
本文介绍了一种表达查询的新方法,这些查询以声明图形状的形式跨越多个表.
此外,本文还包含对这种新方法与EF查询的全面性能比较.该分析表明GBQ快速优于EF查询.
如何构造LINQ to Entities查询以直接加载子对象,而不是调用Reference属性或Load()
没有其他办法 - 除了实现延迟加载.
或手动加载....
myobj = context.MyObjects.First();
myobj.ChildA.Load();
myobj.ChildB.Load();
...
Run Code Online (Sandbox Code Playgroud)