EF Core通过DbContext对象从数据库中读取记录,例如:我们能获取所有的员工记录从数据库中通过使用下面代码:
var emp = context.Employee;这里的context是一个DbContext对象类,employee是从数据库中读取的记录.
我们能从数据库中获取到指定的员工,例如下面查询姓名是Matt员工
var emp = await context.Employee.Where(e => e.Name == "Matt").FirstOrDefaultAsync();预先加载(Eager Loading)模式: 读取该实体时,会同时查询关联表数据,通常会出现表连接查询,查询所有必需数据,可使用 Include 和 ThenInclude 方法实现预先加载
懒加载(Lazy Loading)模式:首次读取实体时,不查询关联数据,然而,首次尝试访问导航属性时,会自动查询导航属性所需的数据,每次首次从导航属性获取数据时,都向数据库发送查询
1.1 预先加载(Eager Loading)模式
public class Employee{public int Id { get; set; }public int DepartmentId { get; set; }public string Name { get; set; }public string Designation { get; set; }public Department Department { get; set; }}
Employee emp = await context.Employee.Where(e => e.Name == "Matt").FirstOrDefaultAsync();运行应用程序,通过断点来检查Department值,我们发现他的值为null,如下图所示:

public Department Department { get; set; }public class Department{public int Id { get; set; }public string Name { get; set; }public ICollection<Employee> Employee { get; set; }}
Employee emp = await context.Employee.Where(e => e.Name == "Matt").Include(s => s.Department).FirstOrDefaultAsync();
我们通过断点查看一下上面代码,我们发现Department属性有值,如下图显示:

read,create,delete,和update数据EF Core 在背后会替我们执行相应的SQL
SELECT [e].[Id], [e].[Designation], [e].[Name], [e.Department].[Id], [e.Department].[Name]FROM [Employee] AS [e]LEFT JOIN [Department] AS [e.Department] ON [e].[DepartmentId] = [e.Department].[Id]WHERE [e].[Name] = N'Matt'
我们能使用多个Include() 方法加载多个引用实体,例如:假如Employee实体有另一个关联实体Project,下面Include代码加载Employee类Department和Project
var emp = await context.Employee.Where(e => e.Name == "Matt").Include(s=>s.Department).Include(s=>s.Project).FirstOrDefaultAsync();
1.1.2 ThenInclude()方法
EF Core 有ThenInclude()方法用来加载多级别关联数据,例如:假设Department实体有一个名字为Report的导航属性
public class Department{public int Id { get; set; }public string Name { get; set; }public ICollection<Employee> Employee { get; set; }public Report Report { get; set; }}
var emp = await context.Employee.Where(e => e.Name == "Matt").Include(s => s.Department).ThenInclude(r => r.Report).FirstOrDefaultAsync();
1.2 显式加载(Explicit Loading)模式
var emp = await context.Employee.Where(e => e.Name == "Matt").FirstOrDefaultAsync();await context.Entry(emp).Reference(s => s.Department).LoadAsync();
context.Entry(emp).Reference(s=>s.Department).LoadAsync()加载Employee实体数据,Department,Reference获取引用关联的数据,LoadAsync()方法加载对应数据


我们可以在Load数据之前使用Query()方法对数据进行过滤
context.Entry(emp).Reference(s=>s.Department).Query().Where(s => s.Name == "Admin").LoadAsync();在使用Lazy Loading之前,我们必须做如下配置:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseLazyLoadingProxies();}
public class Employee{public int Id { get; set; }public int DepartmentId { get; set; }public string Name { get; set; }public string Designation { get; set; }public virtual Department Department { get; set; }}public class Department{public int Id { get; set; }public string Name { get; set; }public virtual ICollection<Employee> Employee { get; set; }}
Lazy Loading例子:
Employee emp = await context.Employee.Where(e => e.Name == "Matt").FirstOrDefaultAsync();string deptName = emp.Department.Name;
上面代码加载Employee实体的Department属性使用了Lazy Loading,通过断点我们能看到departName变量的值。如下图所示:

2 优化EF Core 代码
LINQ查询会跟踪所有的实体状态,这将引发额外开销,在只读的场景下不需要跟踪实体,使用AsNoTracking 方法告诉EF Core 不跟踪实体,我们在代码中能使用它:
var emp = context.Employee.AsNoTracking();var empall = context.Employee;var empmatt = context.Employee.Where(e => e.Name == "Matt").FirstOrDefault();
通过将结果存储到list 类型的对象,我们减少数据库调用次数
var empall = context.Employee.ToList();var empmatt = empall.Where(e => e.Name == "Matt").FirstOrDefault();
限制数据集大小
var empmall = context.Employee.Select(b => b.Name);
var empmatt = context.Employee.Where(e => e.Name == "Matt").Select(b => new {b.Name, b.Designation}).FirstOrDefault();下面代码给我们提供了1,2,3页的数据,并且每页数据为10条
var emp_page_One = context.Employee.Skip(0).Take(10);var emp_page_Two = context.Employee.Skip(20).Take(10);var emp_page_Three = context.Employee.Skip(30).Take(10);
我们将指定EF Core CRUD操作从数据库中读取数据,我们使用Employee和Department实体
打开DepartmentController并且添加Index方法,读取所有department数据,将他们返回到View
public class DepartmentController : Controller{private CompanyContext context;public DepartmentController(CompanyContext cc){context = cc;}public IActionResult Create(){return View();}[HttpPost]public async Task<IActionResult> Create(Department dept){context.Add(dept);await context.SaveChangesAsync();return View();}public IActionResult Index(){return View(context.Department.AsNoTracking());}}
@{ViewData["Title"] = "部门数据";}@model IEnumerable<Department><div class="container"><div class="row mb-3"><div class="col-sm-3"><a asp-action="Create" class="btn btn-secondary">新增</a></div><div class="col-sm-3"></div><div class="col-sm-3"></div><div class="col-sm-3"></div></div><div class="row mb-3"><div class="col-sm"><table class="table table-bordered align-middle"><thead><tr><th>编号</th><th>名称</th></tr></thead><tbody>@foreach (Department dept in Model){<tr><td>@dept.Id</td><td>@dept.Name</td></tr>}</tbody></table></div></div></div>
运行应用程序并打开地https://localhost:7234/Department ,我们能看到所有的部门数据显示在表格内:

public class EmployeeController : Controller{private CompanyContext context;public EmployeeController(CompanyContext cc){context = cc;}public async Task<IActionResult> Index(){//var employee = context.Employee.Where(emp => emp.Name == "Matt")// .Include(s => s.Department)// .FirstOrDefault();//var emp = await context.Employee.Where(e => e.Name == "Matt")// .FirstOrDefaultAsync();//await context.Entry(emp).Reference(s => s.Department).LoadAsync();//Employee emp = await context.Employee.Where(e => e.Name == "Matt")// .FirstOrDefaultAsync();//string deptName = emp.Department.Name;var employee = context.Employee.Where(emp => emp.Name == "Matt").Include(s => s.Department);return View();}}
context.Employee.Include(s => s.Department)@{ViewData["Title"] = "部门数据";}@model IEnumerable<Employee><div class="container"><div class="row mb-3"><div class="col-sm-3"><a asp-action="Create" class="btn btn-secondary">新增</a></div><div class="col-sm-3"></div><div class="col-sm-3"></div><div class="col-sm-3"></div></div><div class="row mb-3"><div class="col-sm"><table class="table table-bordered align-middle"><thead><tr><th>ID</th><th>Name</th><th>Designation</th><th>Department</th></tr></thead><tbody>@foreach (Employee emp in Model){<tr><td>@emp.Id</td><td>@emp.Name</td><td>@emp.Designation</td><td>@emp.Department.Name</td></tr>}</tbody></table></div></div></div>
运行应用程序,输入https://localhost:7234/Employee,我们发现所有的employee显示如下:

总结:
我们主要讲解EF Core读取数据的三种方式,也学习了如何包含子集合当读取关联记录时,我们也讨论了在应用程序中如何优化EF Core,在文章最后我们使用了EF Core进行数据查询,下一节我们讲解EF Core 中如何更新数据