(25)ASP.NET Core EF查询(复杂查询运算符、原生SQL查询、异步查询)
1.复杂查询运算符
在生产场景中,我们经常用到LINQ运算符进行查询获取数据,现在我们就来了解下生产场景经常出现几种复杂查询运算符。
1.1联接(INNER JOIN)
借助LINQ Join运算符,可根据每个源的键选择器连接两个数据源,并在键匹配时生成值的元组。
var query = from blog in _context.Set<Blog>()
join post in _context.Set<Post>()
on blog.BlogId equals post.BlogId
select new { blog, post };
SQL:
SELECT [blog].[BlogId], [blog].[Createtime], [blog].[Updatetime], [blog].[Url], [post].[PostId], [post].[BlogId], [post].[Content], [post].[Title]
FROM [Blog] AS [blog]
INNER JOIN [Post] AS [post] ON [blog].[BlogId] = [post].[BlogId]
SQL Server Profiler:
1.2左联接(Left Join)
虽然Left Join不是LINQ运算符,但关系数据库具有常用于查询的Left Join的概念。LINQ查询中的特定模式提供与服务器上的LEFT JOIN相同的结果。
var query = from blog in _context.Set<Blog>()
join post in _context.Set<Post>()
on blog.BlogId equals post.BlogId into grouping
from post in grouping.DefaultIfEmpty()
select new { blog, post };
SQL:
SELECT [blog].[BlogId], [blog].[Createtime], [blog].[Updatetime], [blog].[Url], [post].[PostId], [post].[BlogId], [post].[Content], [post].[Title]
FROM [Blog] AS [blog]
LEFT JOIN [Post] AS [post] ON [blog].[BlogId] = [post].[BlogId]
SQL Server Profiler:
1.3分组(GroupBy)
LINQ GroupBy运算符创建IGrouping<TKey, TElement>类型的结果,其中TKey和TElement可以是任意类型。此外,IGrouping实现了IEnumerable<TElement>,这意味着可在分组后使用任意LINQ运算符来对其进行组合。
var query = from blog in _context.Set<Blog>()
group blog by blog.Url into g
select new
{
g.Key,
Count = g.Count()
};
SQL:
SELECT [blog].[Url] AS [Key], COUNT(*) AS [Count]
FROM [Blog] AS [blog]
GROUP BY [blog].[Url]
SQL Server Profiler:

分组的聚合运算符出现在Where或OrderBy(或其他排序方式)LINQ运算符中。它在SQL中将Having子句用于Where子句。
var query = from blog in _context.Set<Blog>()
group blog by blog.Url into g
where g.Count() >
orderby g.Key
select new
{
g.Key,
Count = g.Count()
};
SQL:
SELECT [blog].[Url] AS [Key], COUNT(*) AS [Count]
FROM [Blog] AS [blog]
GROUP BY [blog].[Url]
HAVING COUNT(*) >
ORDER BY [Key]
SQL Server Profiler:
EF Core支持的聚合运算符如下所示:
●Avg
●Count
●LongCount
●Max
●Min
●Sum
1.4SelectMany
借助LINQ SelectMany运算符,可为每个外部元素枚举集合选择器,并从每个数据源生成值的元组。
var query0 = from b in _context.Set<Blog>()
from p in _context.Set<Post>()
select new { b, p }; var query1 = from b in _context.Set<Blog>()
from p in _context.Set<Post>().Where(p => b.BlogId == p.BlogId).DefaultIfEmpty()
select new { b, p }; var query2 = from b in _context.Set<Blog>()
from p in _context.Set<Post>().Select(p => b.Url + "=>" + p.Title).DefaultIfEmpty()
select new { b, p };
SQL:
SELECT [b].[BlogId], [b].[Createtime], [b].[Updatetime], [b].[Url], [p].[PostId], [p].[BlogId], [p].[Content], [p].[Title]
FROM [Blog] AS [b]
CROSS JOIN [Post] AS [p] SELECT [b].[BlogId], [b].[Createtime], [b].[Updatetime], [b].[Url], [t0].[PostId], [t0].[BlogId], [t0].[Content], [t0].[Title]
FROM [Blog] AS [b]
CROSS APPLY (
SELECT [t].[PostId], [t].[BlogId], [t].[Content], [t].[Title]
FROM (
SELECT NULL AS [empty]
) AS [empty]
LEFT JOIN (
SELECT [p].[PostId], [p].[BlogId], [p].[Content], [p].[Title]
FROM [Post] AS [p]
WHERE [b].[BlogId] = [p].[BlogId]
) AS [t] ON =
) AS [t0] SELECT [b].[BlogId], [b].[Createtime], [b].[Updatetime], [b].[Url], [t0].[c]
FROM [Blog] AS [b]
CROSS APPLY (
SELECT [t].[c]
FROM (
SELECT NULL AS [empty]
) AS [empty]
LEFT JOIN (
SELECT ([b].[Url] + N'=>') + [p].[Title] AS [c]
FROM [Post] AS [p]
) AS [t] ON =
) AS [t0]
SQL Server Profiler:


好了,这里就不多写关于LINQ其他示例了,如果需要了解的小伙伴们,可以移步“101个LINQ示例”这里了解。
2.原生SQL查询
有一些复杂业务场景,使用LINQ查询可能会导致SQL查询效率低下并不适用,那么这时候就需要到原生SQL查询了。EF Core为我们提供FromSql扩展方法基于原始SQL查询。 FromSql只能在直接位于DbSet<>上的查询根上使用。
var blogs = _context.Blog.FromSql("SELECT * FROM dbo.Blog").ToList();
原生SQL查询可用于执行存储过程。
var blogs = _context.Blog
.FromSql("EXECUTE dbo.GetMostPopularBlogs")
.ToList();
2.1原始SQL查询使用参数化
向原始SQL查询引入任何用户提供的值时,必须注意防范SQL注入攻击。除了验证确保此类值不包含无效字符,还要将值与SQL文本参数化处理。
下面的示例通过在SQL查询字符串中包含形参占位符并提供额外的实参,将单个形参传递到存储过程。虽然此语法可能看上去像String.Format语法,但提供的值包装在DbParameter中,且生成的参数名称插入到指定{0}占位符的位置。
var url = "http://blogs.msdn.com/webdev";
var blogs = _context.Blog
.FromSql("EXECUTE dbo.GetMostPopularBlogForUrl {0}", url)
.ToList();
SQL:
exec sp_executesql N'EXECUTE dbo.GetMostPopularBlogForUrl @p0
',N'@p0 nvarchar()',@p0=N'http://blogs.msdn.com/webdev'
SQL Server Profiler:

还可以构造DbParameter并将其作为参数值提供。由于使用了常规SQL参数占位符而不是字符串占位符,因此可安全地使用FromSql:
var urlParams = new SqlParameter("Url", "http://blogs.msdn.com/webdev");
var blogs = _context.Blog
.FromSql("EXECUTE dbo.GetMostPopularBlogForUrl @Url", urlParams)
.ToList();
SQL:
exec sp_executesql N'EXECUTE dbo.GetMostPopularBlogForUrl @Url
',N'@Url nvarchar()',@Url=N'http://blogs.msdn.com/webdev'
SQL Server Profiler:

2.2使用LINQ编写SQL
可使用LINQ运算符在初始的原始SQL查询基础上进行组合。EF Core将其视为子查询,并在数据库中对其进行组合。下面的示例使用原始SQL查询,该查询从表值函数 (TVF) 中进行选择。然后,使用LINQ进行筛选和排序,从而对其进行组合。
var searchTerm = "http://blogs.msdn.com/visualstudio";
var blogs = _context.Blog
.FromSql($"SELECT * FROM dbo.Blog")
.Where(b => b.Url == searchTerm)
.Include(c=>c.Post)
.OrderByDescending(b => b.Createtime)
.ToList();
SQL:
exec sp_executesql N'SELECT [b].[BlogId], [b].[Createtime], [b].[Updatetime], [b].[Url]
FROM (
SELECT * FROM dbo.Blog
) AS [b]
WHERE [b].[Url] = @__searchTerm_1
ORDER BY [b].[Createtime] DESC, [b].[BlogId]',N'@__searchTerm_1 nvarchar()',@__searchTerm_1=N'http://blogs.msdn.com/visualstudio' exec sp_executesql N'SELECT [b.Post].[PostId], [b.Post].[BlogId], [b.Post].[Content], [b.Post].[Title]
FROM [Post] AS [b.Post]
INNER JOIN (
SELECT [b0].[BlogId], [b0].[Createtime]
FROM (
SELECT * FROM dbo.Blog
) AS [b0]
WHERE [b0].[Url] = @__searchTerm_1
) AS [t] ON [b.Post].[BlogId] = [t].[BlogId]
ORDER BY [t].[Createtime] DESC, [t].[BlogId]',N'@__searchTerm_1 nvarchar()',@__searchTerm_1=N'http://blogs.msdn.com/visualstudio'
SQL Server Profiler:

3.异步查询
当在数据库中执行查询时,异步查询可避免阻塞线程。异步查询对于在客户端应用程序中保持响应式UI非常重要。 异步查询还可以增加Web应用程序中的吞吐量,即通过释放线程,以处理其他Web应用程序中的请求。
public async Task<IActionResult> Index()
{
var id1 = Thread.CurrentThread.ManagedThreadId.ToString(); var blogs = await _context.Blog.ToListAsync(); var id2 = Thread.CurrentThread.ManagedThreadId.ToString(); return View(blogs);
}
当我们运行以上代码时候,通过在关键字await上下文加入两段获取线程ID代码,我们会看到如下结果:
看到两段线程代码输出ID结果没有?从上图可以观察到,当我们在进入某个视图或者方法时候,执行到await某一个方法,当前线程不会一直等待下去,会立马回收到线程池,供其他地方调用!当该await方法返回数据时候,才从线程池调用空闲线程执行await方法下文余下的步骤。所以UI界面才不会进入假死状态。
(25)ASP.NET Core EF查询(复杂查询运算符、原生SQL查询、异步查询)的更多相关文章
- asp.net core+ef core
asp.net core+ef core 官方的文档https://docs.asp.net/en/latest/tutorials/first-mvc-app/start-mvc.html 先来看一 ...
- C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制
在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.Net Core的缓存机制. 关于.Net Core的缓存,官方有三种实现: 1.In Memory Cachi ...
- Asp.net Core + EF Core + Bootstrap搭建的MVC后台通用管理系统模板(跨平台版本)
Asp.net Core + EF Core + Bootstrap搭建的MVC后台通用管理系统模板(跨平台版本) 原创 2016年07月22日 10:33:51 23125 6月随着.NET COR ...
- ASP.NET Core EF 查询获取导航属性值,使用Include封装
// 引用 using Microsoft.EntityFrameworkCore; // 摘要: // Specifies related entities to include in the qu ...
- (24)ASP.NET Core EF查询(查询的工作原理、跟踪与非跟踪查询)
1.查询生命周期 在进入正题时候,我们先来了解EF Core查询的生命周期. 1.1LINQ查询会由Entity Framework Core处理并生成给数据库提供程序可处理的表示形式(说白了就是生成 ...
- C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现
今天做一个管理后台菜单,想着要用无限极分类,记得园子里还是什么地方见过这种写法,可今天找了半天也没找到,没办法静下心来自己写了: 首先创建节点类(我给它取名:AdminUserTree): /// & ...
- ASP.NET Core&EF 笔记
首先创建Asp.net Core项目,然后通过 NuGet 安装 EntityFrameworkCore: Microsoft.EntityFrameworkCore.SqlServer Micros ...
- (17)ASP.NET Core EF基于数据模型创建数据库
1.简介 使用Entity Framework Core构建执行基本数据访问的ASP.NET Core MVC应用程序.使用迁移(Migrations)基于数据模型创建数据库,你可以在Windows上 ...
- ASp.net Core EF ActionFilterAttribute AOP
在项目中经常遇到一些数据的修改,很多时候业务方需要一个修改日志记录,这里我们计划用mssql数据库来存放日志记录,用EF来操作,记录日志可以用mvc的ActionFilterAttribute 来完成 ...
随机推荐
- 关于javascript中的prototype
作为一个致力于前端开发的人员,能够熟练掌握javascript的原理和机制是每个小白的必经之路,这也是最痛苦的.有人说前端功力好不好最主要的就是看对js的掌握能力,有人说十年也啃不完一门javascr ...
- Windows 10 删除C盘的用户,恢复技巧
起因 入域不成功,然后强制删除了C盘 Users里面 账户 然后再进行入域的时候就入域不成功了,如果再进行登录就会提示 无法登录到你的账户 通常可以通过从你的账户注销,然后重新登录解决此问题 如果不立 ...
- react 首屏性能优化
首屏优化点:1.加载包(bundle.js)文件的大小,越小,首屏渲染速度越快 (按需加载) 2.优先渲染用户直观看到的页面部分(懒加载) 技术点:react-loadable . react-laz ...
- CSS3属性—— line-clamp控制文本行数
说明: 限制在一个块元素显示的文本的行数. -webkit-line-clamp 是一个 不规范的属性(unsupported WebKit property),它没有出现在 CSS 规范草案中. 为 ...
- AVL树、红黑树以及B树介绍
简介 首先,说一下在数据结构中为什么要引入树这种结构,在我们上篇文章中介绍的数组与链表中,可以发现,数组适合查询这种静态操作(O(1)),不合适删除与插入这种动态操作(O(n)),而链表则是适合删除与 ...
- Java课程作业--参数求和
一.设计思想: 这个程序是利用了参数进行输入,达到一次可以输入多个值的问题,同时输入数的个数没有限制(参数大于0个,如果为0个,应该输出提示请输入参数).本程序共分为步:1.利用参数行进行输入要加的数 ...
- Vijos 1067守望者的烦恼
背景 守望者-warden,长期在暗夜精灵的的首都艾萨琳内担任视察监狱的任务,监狱是成长条行的,守望者warden拥有一个技能名叫“闪烁”,这个技能可以把她传送到后面的监狱内查看,她比较懒,一般不查看 ...
- PowerBI系列之什么是PowerBI
大家好,我是小黎子!一个专注于数据分析整体数据仓库解决方案的程序猿!今天小黎子就给大家介绍一个数据分析工具由Microsoft出品的全新数据可视化工具Power BI.微软Excel很早就支持了数据透 ...
- C# .Net Framework
.NET Framework概述 .NET Framework是由微软开发,一个致力于敏捷软件开发.快速应用开发.平台无关性和网络透明化的软件开发平台. .NET Framework组成 .NET F ...
- web开发基础之HTTP协议
HTTP协议 HTTP协议简介 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议.HTTP是万维网的数 ...