Entity Framework Core 允许你在模型中使用导航属性来加载相关实体。 有三种常见的 O/RM 模式可用于加载关联数据。
- 预先加载表示从数据库中加载关联数据,作为初始查询的一部分。
- 显式加载表示稍后从数据库中显式加载关联数据。
- 延迟加载表示在访问导航属性时,从数据库中以透明方式加载关联数据
这里仅结束第一种,使用Include的方式。
什么是关联的数据?
如下图,两个导航属性Assets以及Department,分别对应两个外键AssetsId以及DepartmentId,关联到另外两张表上。需要查询到当前的实体关联到另外两张表中的信息,比如部门名称,资产名称等,就需要通过关联查询去把数据加载到本次查询的结果中来。
实际上,要查询出关联表的数据信息,可以通过以下两种方法
(1)通过外键,去把对应的实体信息查询出来。
(2)通过导航属性,加载关联数据到查询结果中,形如类似下图
这里可能有人会问,导航属性本身没有携带任何关于某个特定实体关于另一张表的标记信息,也就是说,EF core如何将各个实体将属于他的关联信息匹配起来呢?
答案在这里,如下图
实际上,通过Include的关联查询最终也将通过外键去查询并加载相关的数据到结果中,用Include的好处是简化代码(代价是牺牲性能),假如直接操作使用外键进行查询,上面的查询就会变成如下图所示
这样写看起来麻烦,其实当有想取出很多层的关联信息的时候,性能还是要好过下面的多个include嵌套的。。。
包含多个层级
使用 ThenInclude
方法可以依循关系包含多个层级的关联数据。 以下示例加载了所有博客、其关联文章及每篇文章的作者。
using (var context = new BloggingContext())
{
var blogs = context.Blogs
.Include(blog => blog.Posts)
.ThenInclude(post => post.Author)
.ToList();
}
可通过链式调用 ThenInclude
,进一步包含更深级别的关联数据。
using (var context = new BloggingContext())
{
var blogs = context.Blogs
.Include(blog => blog.Posts)
.ThenInclude(post => post.Author)
.ThenInclude(author => author.Photo)
.ToList();
}
可以将来自多个级别和多个根的关联数据合并到同一查询中。
using (var context = new BloggingContext())
{
var blogs = context.Blogs
.Include(blog => blog.Posts)
.ThenInclude(post => post.Author)
.ThenInclude(author => author.Photo)
.Include(blog => blog.Owner)
.ThenInclude(owner => owner.Photo)
.ToList();
}
有人会问,这样性能不会很差吗?
实际上这并不意味着会获得冗余联接查询,在大多数情况下,EF 会在生成 SQL 时合并相应的联接查询。
经过筛选的关联查询
支持的操作包括:Where
、OrderBy
、OrderByDescending
、ThenBy
、ThenByDescending
、Skip
和 Take
。
对blog的关联实体post进行筛选,排序,操作
using (var context = new BloggingContext())
{
var filteredBlogs = context.Blogs
.Include(blog => blog.Posts
.Where(post => post.BlogId == 1)
.OrderByDescending(post => post.Title)
.Take(5))
.ToList();
}
只能对每个包含的导航执行一组唯一的筛选器操作。 如果为某个给定的集合导航应用了多个包含操作(下例中为 blog.Posts
),则只能对其中一个导航指定筛选器操作。
在这里就是只能对blog的关联实体post上的某一个关联实体,Author或者Tag进行筛选排序操作,这里是对Tag进行的,
由于第一个Include对Post进行了Where过滤,直接对post的关联实体Tag进行排序筛选操作
多层不建议这么写,会性能会很差。。。。,分开查就好了
using (var context = new BloggingContext())
{
var filteredBlogs = context.Blogs
.Include(blog => blog.Posts.Where(post => post.BlogId == 1))
.ThenInclude(post => post.Author)
.Include(blog => blog.Posts)
.ThenInclude(post => post.Tags.OrderBy(postTag => postTag.TagId).Skip(3))
.ToList();
}