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 中如何更新数据