EF Core使用Linq进行数据查询。

基本查询

微软提供了一百多个示例来演示查询,地址:https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b

我们可以通过下面的代码进行简单的查询:

//获取全部数据
var blogs = context.Blogs.ToList(); //获取单个实体
var blog = context.Blogs.Single(b => b.BlogId == 1); //筛选
var blogs = context.Blogs
.Where(b => b.Url.Contains("dotnet"))
.ToList();

加载关联数据

EF Core有三种常见模型来加载关联数据:

  • 预先加载:表示从数据库中加载关联数据,作为初始查询的一部分
  • 显式加载:表示稍后从数据库中显式加载关联数据
  • 延迟加载:表示在访问关联数据时,再从数据库中加载关联数据

预先加载

使用Include方法指定要包含在查询结果中的关联数据。例如:

using (var context = new BloggingContext())
{
var blogs = context.Blogs
.Include(blog => blog.Posts)
.Include(blog => blog.Owner)
.ToList();
}

关联数据可以是有层级的,可通过链式调用ThenInclude,进一步包含更深级别的关联数据。:

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();
}

如果更改查询,从而使其不再返回查询以之为开头的实体类型的实例,则会忽略 include 运算符。例如:

using (var context = new BloggingContext())
{
var blogs = context.Blogs
.Include(blog => blog.Posts)
.Select(blog => new
{
Id = blog.BlogId,
Url = blog.Url
})
.ToList();
}

此时EF Core会忽略包含,并生成警告日志。

显式加载

通过 DbContext.Entry(...) API 显式加载导航属性。例如:

using (var context = new BloggingContext())
{
var blog = context.Blogs
.Single(b => b.BlogId == 1); context.Entry(blog)
.Collection(b => b.Posts)
.Load(); context.Entry(blog)
.Reference(b => b.Owner)
.Load();
}

延迟加载

使用延迟加载的最简单方式是通过安装 Microsoft.EntityFrameworkCore.Proxies 包,并通过调用 UseLazyLoadingProxies 来启用该包。 例如:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString);

或者在ServiceConfigure中,调用services.AddDbContext方法时启用:

services.AddDbContext<BloggingContext>(
b => b.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString));

EF Core 延迟加载需要属性必须具有是共有的,且具有virtual修饰符,只有这样才可以被子类重写。为何要这样做,可以参考我之前的文章《Castle DynamicProxy基本用法(AOP)》。

下面的代码演示了延迟加载的用法:

public class Blog
{
public int Id { get; set; }
public string Name { get; set; } public virtual ICollection<Post> 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; }
}

此时EF Core会使用代理类进行延迟加载数据。

EF Core还提供了不使用代理的方式进行延迟加载,此方法需要向实体类中注入ILazyLoader实例,并通过该实例实现get访问:

public class Blog
{
private ICollection<Post> _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 ICollection<Post> Posts
{
get => LazyLoader.Load(this, ref _posts);
set => _posts = value;
}
}

此种方法需要注入ILazyLoader,从而造成更多的包依赖。

使用EF Core延迟加载,可能会造成循环引用,此时无法使用Json.Net进行序列化,需要对此进行一些配置:

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
}

客户端 vs. 服务器

EF Core支持部分查询在客户端进行、部分查询发送到服务器,此种情况下可能会造成性能问题。

当发生客户端筛选数据的时候,EF Core会发出警告,也可以配置当发生客户端筛选时抛出异常:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;")
.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}

跟踪和非跟踪

默认情况下,EF Core跟踪查询返回的实体,如果我们不需要跟踪查询返回的实体,则可以通过AsNoTracking方法禁用跟踪。

using (var context = new BloggingContext())
{
var blogs = context.Blogs
.AsNoTracking()
.ToList();
}

或者在DbContext级别禁用跟踪:

using (var context = new BloggingContext())
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var blogs = context.Blogs.ToList();
}

当使用投影查询结果时,如果包含实体类型,则会对实体类型执行跟踪,例如下面的查询,将会对Blog和Post进行跟踪:

using (var context = new BloggingContext())
{
var blog = context.Blogs
.Select(b =>
new
{
Blog = b,
Posts = b.Posts.Count()
});
}

另外,如果查询结果中不包含任何实体类型,则不执行跟踪。例如:

using (var context = new BloggingContext())
{
var blog = context.Blogs
.Select(b =>
new
{
Id = b.BlogId,
Url = b.Url
});
}

原始SQL查询

当Linq无法满足查询需求,或因为使用Linq生成效率比较低的SQL查询时,可以考虑使用原始SQL进行查询。EF Core支持原始SQL语句和存储过程。

原始SQL语句:

var blogs = context.Blogs
.FromSql("SELECT * FROM dbo.Blogs")
.ToList();

存储过程:

var blogs = context.Blogs
.FromSql("EXECUTE dbo.GetMostPopularBlogs")
.ToList();

参数传递

当使用原始SQL进行查询时,必须使用参数化查询以抵御SQL注入攻击。

好的一点是,EF Core在设计时就替我们考虑了如何防御SQL注入攻击,因此当我们使用FromSql方法时,参数中如果有使用到拼接字符串的情况,则会自动为我们生成SQL查询参数,例如:

var user = "johndoe";

var blogs = context.Blogs
.FromSql($"EXECUTE dbo.GetMostPopularBlogsForUser {user}")
.ToList();

上面的SQL语句虽然看上去像是直接拼接的字符串,其实EF Core已经为我们生成了查询参数。

当然了,我们也可以手工创建查询参数:

var user = new SqlParameter("user", "johndoe");

var blogs = context.Blogs
.FromSql("EXECUTE dbo.GetMostPopularBlogsForUser @user", user)
.ToList();

当数据库的存储过程使用了命名参数时,手工创建查询参数将会派上用场:

var user = new SqlParameter("user", "johndoe");

var blogs = context.Blogs
.FromSql("EXECUTE dbo.GetMostPopularBlogs @filterByUser=@user", user)
.ToList();

拼接Linq

当我们使用原始SQL查询时,EF Core仍然支持我们使用linq编写查询语句。在执行查询时,EF Core会检查我们的sql语句是否支持拼接,如果支持的情况下,则会将linq过滤语句拼接为sql一并发送到数据库进行查询。

跟踪

原始SQL中的跟踪与Linq查询的跟踪方式一致。

关联数据

原始SQL中查询关联数据的方式与Linq查询的关联方式一致。

全局筛选器

全局筛选器对于软删除和多租户非常有用。定义方式如下:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().Property<string>("TenantId").HasField("_tenantId"); // Configure entity filters
modelBuilder.Entity<Blog>().HasQueryFilter(b => EF.Property<string>(b, "TenantId") == _tenantId);
modelBuilder.Entity<Post>().HasQueryFilter(p => !p.IsDeleted);
}

我们可以在特定的查询中禁用全局筛选器:

blogs = db.Blogs
.Include(b => b.Posts)
.IgnoreQueryFilters()
.ToList();

03-EF Core笔记之查询数据的更多相关文章

  1. EntityFramework Core笔记:查询数据(3)

    1. 基本查询 1.1 加载全部数据 using System.Linq; using (var context = new LibingContext()) { var roles = contex ...

  2. 深入理解 EF Core:使用查询过滤器实现数据软删除

    原文:https://bit.ly/2Cy3J5f 作者:Jon P Smith 翻译:王亮 声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的.其中可能会去除一些本人实在不知道如何组织 ...

  3. EF Core 的关联查询

    0 前言 本文会列举出 EF Core 关联查询的方法: 在第一.二.三节中,介绍的是 EF Core 的基本能力,在实体中配置好关系,即可使用,且其使用方式,与编程思维吻合,是本文推荐的方式. 第四 ...

  4. EF Core利用Transaction对数据进行回滚保护

    What? 首先,说一下什么是EF Core中的Transaction Transaction允许以原子方式处理多个数据库操作,如果事务已提交,则所有操作都应用于数据库,如果事务回滚,则没有任何操作应 ...

  5. 02-EF Core笔记之保存数据

    EF Core通过ChangeTracker跟踪需要写入数据库的更改,当需要保存数据时,调用DbContext的SaveChanges方法完成保存. 基本的添加.更新.删除操作示例如下: using ...

  6. EF Core 使用编译查询提高性能

    今天,我将向您展示这些EF Core中一个很酷的功能,通过使用显式编译的查询,提高查询性能. 不过在介绍具体内容之前,需要说明一点,EF Core已经对表达式的编译使用了缓存:当您的代码需要重用以前执 ...

  7. EF core的原生SQL查询以及用EF core进行分页查询遇到的问题

    在用.net core进行数据库访问,需要处理一些比较复杂的查询,就不得不用原生的SQL查询了,然而EF Core 和EF6 的原生sql查询存在很大的差异. 在EF6中我们用SqlQuery和Exe ...

  8. Dapper, Ef core, Freesql 插入大量数据性能比较(一)

    需求:导入9999行数据时Dapper, Ef core, Freesql 谁的性能更优,是如何执行的,级联增加谁性能更佳. 确认方法:sql server 的 sys.dm_exec_query_s ...

  9. oracle系列笔记(1)---查询数据

    查询数据 1. 查询(select .. form ..)    (1)普通查询 select * from employees --代表查询employees表中所有数据 select last_n ...

随机推荐

  1. MySQL通过自定义函数实现递归查询父级ID或者子级ID

    背 景: 在MySQL中如果是有限的层次,比如我们事先如果可以确定这个树的最大深度, 那么所有节点为根的树的深度均不会超过树的最大深度,则我们可以直接通过left join来实现. 但很多时候我们是无 ...

  2. 生成Alpine LXC容器的根文件系统

    一个Alpine LXC容器的文件系统内容包括以下内容 根文件系统 应用程序,库文件以及配置文件 根文件系统主要包含alpine linux最小系统所需要的组件.下面主要讲一下制作根文件系统的方法. ...

  3. TypeScript SDK 和 REST API

    在本文中,我们将讨论CUBA平台中已经存在很长时间的一个功能,但是很多人还不知道,这就是前端SDK生成器,并了解它如何与CUBA的REST API插件一起使用. Java+JavaScript - 在 ...

  4. PostGIS 存储过程返回类型

    Postgresql存储过程返回值的方式有很多,在此先只记录一下自己用到过的,慢慢拓展 1.type型,这里geometry可以是任何postgresql支持的类型(integer/text/char ...

  5. web网站常用功能测试点总结

    目录 一.输入框 二.搜索功能 三.添加.修改功能 四.删除功能 五.注册.登录模块 六.上传图片测试 七.查询结果列表 八.返回键检查 九.回车键检查 十.刷新键检查 十一.直接URL链接检查 十二 ...

  6. 从零开始手写 spring ioc 框架,深入学习 spring 源码

    IoC Ioc 是一款 spring ioc 核心功能简化实现版本,便于学习和理解原理. 创作目的 使用 spring 很长时间,对于 spring 使用非常频繁,实际上对于源码一直没有静下心来学习过 ...

  7. 12、pytest -- 缓存:记录执行的状态

    目录 1. cacheprovider插件 1.1. --lf, --last-failed:只执行上一轮失败的用例 1.2. --ff, --failed-first:先执行上一轮失败的用例,再执行 ...

  8. JAVA中数组Arrays类的常见用法

    import java.util.Arrays; int[] array1={7,8,3,2,12,6,5,4}; 1.  //克隆clone  int[] array2=array1.clone() ...

  9. 转载-FileZilla Server源码分析(1)

    FileZilla Server源码分析(1) 分类: VC 2012-03-27 17:32 2363人阅读 评论(0) 收藏 举报 serversocketftp服务器usersockets工作 ...

  10. 英语口语考试资料Food

    新东方推荐文章:Food and Health The food we eat seems to have profound effects on our health. Although scien ...