efcore 给出的关联数据加载的方式有三种:Eager Loading、Explicit Loading、Lazy Loading,其实还有一种,下面再说( •̀ ω •́ )。
Eager Loading(预先加载)
还是用上一篇文章创建的实体做下演示
/// <summary>
/// EagerLoading
/// </summary>
/// <returns></returns>
public static object StudentEagerLoading()
{
using (var dbContext = new AppDbContext())
{
//使用Include一次查询出导航属性 StudentCourses
var student = dbContext.Students.Include(s=>s.StudentCourses)
.FirstOrDefault();
//StudentCourses集合已经加载
foreach (var course in student.StudentCourses)
{
Console.WriteLine($"{course.CourseId}");
}
return student;
}
}
这种加载方式使用起来很方便,尤其是在应对复杂的业务逻辑时。缺点是,预先加载会加载所有数据,包括我们当不需要的那部分。
Explicti Loading(显式加载)
/// <summary>
/// 显示加载
/// </summary>
/// <returns></returns>
public static Student StudentExplicitLoading()
{
using (var dbContext = new AppDbContext())
{
//先查询出student
var student = dbContext.Students.First();
//加载StudentCourses
dbContext.Entry(student).Collection(s=>s.StudentCourses).Load();
foreach(var studentCourse in student.StudentCourses)
{
//加载Course
dbContext.Entry(studentCourse).Reference(s => s.Course).Load();
Console.WriteLine($"{studentCourse.Course.CourseName}");
}
return student;
}
}
Explicit Loading使用Entry方法,对于集合使用Collection,单个实体使用Reference
Lazy Loading (延迟加载)
Lazy Loading是指在访问导航属性时,才去数据库中加载关联数据,这个过程不需要显式指定加载数据。
Lazy Loading有两种方式实现 推荐第一种引用包 Microsoft.EntityFrameworkCore.Proxies,具体可以参考:https://docs.microsoft.com/zh-cn/ef/core/querying/related-data
开启延迟加载的条件是 导航属性必须设为virtual,并且这个类不是可被继承的(非Sealed)
修改 OnConfiguring方法
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies().UseMySql(ConnStr);
}
/// <summary>
/// 延迟加载
/// </summary>
/// <returns></returns>
public static Student StudentLazyLoading()
{
using (var dbContext = new AppDbContext())
{
//先查询出student
var student = dbContext.Students.First();
//查出studentCourses
var studentCourses = student.StudentCourses.ToList();
foreach(var studentCourse in studentCourses)
{
var course = studentCourse.Course;
Console.WriteLine($"{course.CourseName}");
}
return student;
}
}
最后一种加载关联数据的方式,Select Loading选择加载
选择加载是指从关联的实体中加载只需要的那部分
/// <summary>
/// 选择加载
/// </summary>
/// <returns></returns>
public static string StudentSelectLoading()
{
using (var dbContext = new AppDbContext())
{
var data = dbContext.Students.Select(s => new
{
s.StudentName,
s.StudentCourses.First().Course.CourseName
}).First();
return JsonConvert.SerializeObject(data);
}
}
Json序列化这里需要注意一下循环引用的问题,可以参考https://docs.microsoft.com/zh-cn/ef/core/querying/related-data#related-data-and-serialization解决