景点介绍网站模板,软件开发项目管理办法,wordpress官方的三个主题好排名,淘宝客网站空间【Entity Framework】你必须要了解EF中数据查询之数据加载 文章目录 【Entity Framework】你必须要了解EF中数据查询之数据加载一、概述二、预先加载2.1 包含多个层级2.2 经过筛选的包含 三、显示加载3.1查询关联实体 四、延时加载4.1 不使用代理进行延迟加载 一、概述
Entity…【Entity Framework】你必须要了解EF中数据查询之数据加载 文章目录 【Entity Framework】你必须要了解EF中数据查询之数据加载一、概述二、预先加载2.1 包含多个层级2.2 经过筛选的包含 三、显示加载3.1查询关联实体 四、延时加载4.1 不使用代理进行延迟加载 一、概述
Entity Framework Core允许在模型中使用导航属性来加载关联实体。有三种常见的O/RM模式可用于加载关联数据。
预先加载表示从数据库中加载关联数据作为初始查询的一部分显示加载表示稍后从数据库中显示加载关联数据延迟加载表示在访问导航属性时从数据库中以透明方式加载关联数据
二、预先加载
可以使用Include方法来指定要包含在查询结果中的关联数据。如示例结果中结果中返回的blogs将使用关联的posts填充其posts属性。
using (var context new BloggingContext())
{var blogs context.Blogs.Include(blog blog.Posts).ToList();
}Entity Framework Core 会根据之前已加载到上下文实例中的实体自动填充导航属性。 因此即使不显式包含导航属性的数据如果先前加载了部分或所有关联实体则仍可能填充该属性。 可以在单个查询中包含多个关系的关联数据。
using (var context new BloggingContext())
{var blogs context.Blogs.Include(blog blog.Posts).Include(blog blog.Owner).ToList();
}2.1 包含多个层级
使用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 contextnew BloggingContext())
{var blogs context.Blogs.Include(blog blog.Posts).ThenInclude(post post.Author).ThenInclude(author post.Photo).Include(blog blog.Owner).ThenInclude(owner owner.Photo).ToList();
}你可能希望将已包含的某个实体的多个关联实体都包含进来。 例如当查询 Blogs 时你会包含 Posts然后希望同时包含 Posts 的 Author 和 Tags。 为了包含这两项内容需要从根级别开始指定每个包含路径。 例如Blog - Posts - Author 和 Blog - Posts - Tags。 这并不意味着会获得冗余联接查询在大多数情况下EF 会在生成 SQL 时合并相应的联接查询。
using (var context new BloggingContext())
{var blogs context.Blogs.Include(blog blog.Posts).ThenInclude(post post.Author).Include(blog blog.Posts).ThenInclude(post post.Tags).ToList();
}2.2 经过筛选的包含
在应用包含功能来加载相关数据时可对已包含的集合导航应用某些可枚举的操作这样就可以对结果进行筛选和排序。
支持的操作包括Where、OrderBy、OrderByDescending、ThenBy、ThenByDescending、Skip和Take。
应对传递到Include方法的Lambda中的集合导航应用这类操作。如下例所示
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();
}可对多次包含的每个导航应用相同的操作
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.Where(post post.BlogId 1)).ThenInclude(post post.Tags.OrderBy(postTag postTag.TagId).Skip(3)).ToList();
}三、显示加载
可以通过DbContext.Entry(...) API显示加载导航属性。
using(var contextnew BloggingContext())
{var blog Context.Blogs.Single(bb.BlogId 1);context.Entry(blog).Collection(bb.Posts).Load();context.Entry(blog).Reference(b b.Owner).Load();
}还可以通过执行返回关联实体的单独查询来显式加载导航属性。 如果已启用更改跟踪则在查询具体化实体时EF Core 将自动设置新加载的实体的导航属性以引用任何已加载的实体并设置已加载实体的导航属性以引用新加载的实体。
3.1查询关联实体
可以获得表示导航属性内容的LINQ查询。
这使你可对查询应用其他运算符。示例
using (var context new BloggingContext())
{var blog context.Blogs.Single(b b.BlogId 1);var postCount context.Entry(blog).Collection(b b.Posts).Query().Count();
}还可以筛选要加载到内存中的关联实体。
using (var context new BloggingContext())
{var blog context.Blogs.Single(b b.BlogId 1);var goodPosts context.Entry(blog).Collection(b b.Posts).Query().Where(p p.Rating 3).ToList();
}四、延时加载
使用延迟加载的最简单方法是通过安装Microsoft.EntityFrameworkCore.Proxies包并通过调用UseLazyLoadingProxies来启动该包。
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) optionsBuilder.UseLazyLoadingProxies().UseSqlServer(myConnectionString);或在使用 AddDbContext 时
.AddDbContextBloggingContext(b b.UseLazyLoadingProxies().UseSqlServer(myConnectionString));EF Core将为可被重写的任何导航属性启用延迟加载。
public class Blog
{public int Id { get; set; }public string Name { get; set; }public virtual ICollectionPost Posts { get; set; }
}public class Post
{public int Id { get; set; }public string Title { get; set; }public string Content { get; set; }public virtual Blog Blog { get; set; }
}4.1 不使用代理进行延迟加载
不使用代理进行延迟加载的工作方式是将 ILazyLoader 注入到实体中如实体类型构造函数中所述。例如
public class Blog
{private ICollectionPost _posts;public Blog(){}private Blog(ILazyLoader lazyLoader){LazyLoader lazyLoader;}private ILazyLoader LazyLoader { get; set; }public int Id { get; set; }public string Name { get; set; }public ICollectionPost Posts{get LazyLoader.Load(this, ref _posts);set _posts value;}
}public class Post
{private Blog _blog;public Post(){}private Post(ILazyLoader lazyLoader){LazyLoader lazyLoader;}private ILazyLoader LazyLoader { get; set; }public int Id { get; set; }public string Title { get; set; }public string Content { get; set; }public Blog Blog{get LazyLoader.Load(this, ref _blog);set _blog value;}
}此方法不要求实体类型为可继承的类型也不要求导航属性必须是虚拟的且允许通过new创建的实体实例在附加到上下文后可进行延迟加载。但它需要对Microsoft.EntityFrameworkCore.Abstractions包中定义的ILazyLoader服务的引用。此包包含所允许的最少的一组类型以便将依赖此包时所产生的影响将到最低。不过可以将ILazyLoader.Load方法以委托的形式注入这样就可以完全避免依赖于实体类型的任何EF Core包。
public class Blog
{private ICollectionPost _posts;public Blog(){}private Blog(Actionobject, string lazyLoader){LazyLoader lazyLoader;}private Actionobject, string LazyLoader { get; set; }public int Id { get; set; }public string Name { get; set; }public ICollectionPost Posts{get LazyLoader.Load(this, ref _posts);set _posts value;}
}public class Post
{private Blog _blog;public Post(){}private Post(Actionobject, string lazyLoader){LazyLoader lazyLoader;}private Actionobject, string LazyLoader { get; set; }public int Id { get; set; }public string Title { get; set; }public string Content { get; set; }public Blog Blog{get LazyLoader.Load(this, ref _blog);set _blog value;}
}上述代码使用 Load 扩展方法以便更干净地使用委托
public static class PocoLoadingExtensions
{public static TRelated LoadTRelated(this Actionobject, string loader,object entity,ref TRelated navigationField,[CallerMemberName] string navigationName null)where TRelated : class{loader?.Invoke(entity, navigationName);return navigationField;}
}