1.复杂查询运算符

在生产场景中,我们经常用到LINQ运算符进行查询获取数据,现在我们就来了解下生产场景经常出现几种复杂查询运算符。

1.1联接(INNER JOIN)

借助LINQ Join运算符,可根据每个源的键选择器连接两个数据源,并在键匹配时生成值的元组。

  1. var query = from blog in _context.Set<Blog>()
  2. join post in _context.Set<Post>()
  3. on blog.BlogId equals post.BlogId
  4. select new { blog, post };

SQL:

  1. SELECT [blog].[BlogId], [blog].[Createtime], [blog].[Updatetime], [blog].[Url], [post].[PostId], [post].[BlogId], [post].[Content], [post].[Title]
  2. FROM [Blog] AS [blog]
  3. 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相同的结果。

  1. var query = from blog in _context.Set<Blog>()
  2. join post in _context.Set<Post>()
  3. on blog.BlogId equals post.BlogId into grouping
  4. from post in grouping.DefaultIfEmpty()
  5. select new { blog, post };

SQL:

  1. SELECT [blog].[BlogId], [blog].[Createtime], [blog].[Updatetime], [blog].[Url], [post].[PostId], [post].[BlogId], [post].[Content], [post].[Title]
  2. FROM [Blog] AS [blog]
  3. 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运算符来对其进行组合。

  1. var query = from blog in _context.Set<Blog>()
  2. group blog by blog.Url into g
  3. select new
  4. {
  5. g.Key,
  6. Count = g.Count()
  7. };

SQL:

  1. SELECT [blog].[Url] AS [Key], COUNT(*) AS [Count]
  2. FROM [Blog] AS [blog]
  3. GROUP BY [blog].[Url]

SQL Server Profiler:


分组的聚合运算符出现在Where或OrderBy(或其他排序方式)LINQ运算符中。它在SQL中将Having子句用于Where子句。

  1. var query = from blog in _context.Set<Blog>()
  2. group blog by blog.Url into g
  3. where g.Count() >
  4. orderby g.Key
  5. select new
  6. {
  7. g.Key,
  8. Count = g.Count()
  9. };

SQL:

  1. SELECT [blog].[Url] AS [Key], COUNT(*) AS [Count]
  2. FROM [Blog] AS [blog]
  3. GROUP BY [blog].[Url]
  4. HAVING COUNT(*) >
  5. ORDER BY [Key]

SQL Server Profiler:

EF Core支持的聚合运算符如下所示:
●Avg
●Count
●LongCount
●Max
●Min
●Sum

1.4SelectMany

借助LINQ SelectMany运算符,可为每个外部元素枚举集合选择器,并从每个数据源生成值的元组。

  1. var query0 = from b in _context.Set<Blog>()
  2. from p in _context.Set<Post>()
  3. select new { b, p };
  4.  
  5. var query1 = from b in _context.Set<Blog>()
  6. from p in _context.Set<Post>().Where(p => b.BlogId == p.BlogId).DefaultIfEmpty()
  7. select new { b, p };
  8.  
  9. var query2 = from b in _context.Set<Blog>()
  10. from p in _context.Set<Post>().Select(p => b.Url + "=>" + p.Title).DefaultIfEmpty()
  11. select new { b, p };

SQL:

  1. SELECT [b].[BlogId], [b].[Createtime], [b].[Updatetime], [b].[Url], [p].[PostId], [p].[BlogId], [p].[Content], [p].[Title]
  2. FROM [Blog] AS [b]
  3. CROSS JOIN [Post] AS [p]
  4.  
  5. SELECT [b].[BlogId], [b].[Createtime], [b].[Updatetime], [b].[Url], [t0].[PostId], [t0].[BlogId], [t0].[Content], [t0].[Title]
  6. FROM [Blog] AS [b]
  7. CROSS APPLY (
  8. SELECT [t].[PostId], [t].[BlogId], [t].[Content], [t].[Title]
  9. FROM (
  10. SELECT NULL AS [empty]
  11. ) AS [empty]
  12. LEFT JOIN (
  13. SELECT [p].[PostId], [p].[BlogId], [p].[Content], [p].[Title]
  14. FROM [Post] AS [p]
  15. WHERE [b].[BlogId] = [p].[BlogId]
  16. ) AS [t] ON =
  17. ) AS [t0]
  18.  
  19. SELECT [b].[BlogId], [b].[Createtime], [b].[Updatetime], [b].[Url], [t0].[c]
  20. FROM [Blog] AS [b]
  21. CROSS APPLY (
  22. SELECT [t].[c]
  23. FROM (
  24. SELECT NULL AS [empty]
  25. ) AS [empty]
  26. LEFT JOIN (
  27. SELECT ([b].[Url] + N'=>') + [p].[Title] AS [c]
  28. FROM [Post] AS [p]
  29. ) AS [t] ON =
  30. ) AS [t0]

SQL Server Profiler:


好了,这里就不多写关于LINQ其他示例了,如果需要了解的小伙伴们,可以移步“101个LINQ示例”这里了解。

2.原生SQL查询

有一些复杂业务场景,使用LINQ查询可能会导致SQL查询效率低下并不适用,那么这时候就需要到原生SQL查询了。EF Core为我们提供FromSql扩展方法基于原始SQL查询。 FromSql只能在直接位于DbSet<>上的查询根上使用。

  1. var blogs = _context.Blog.FromSql("SELECT * FROM dbo.Blog").ToList();

原生SQL查询可用于执行存储过程。

  1. var blogs = _context.Blog
  2. .FromSql("EXECUTE dbo.GetMostPopularBlogs")
  3. .ToList();

2.1原始SQL查询使用参数化

向原始SQL查询引入任何用户提供的值时,必须注意防范SQL注入攻击。除了验证确保此类值不包含无效字符,还要将值与SQL文本参数化处理。
下面的示例通过在SQL查询字符串中包含形参占位符并提供额外的实参,将单个形参传递到存储过程。虽然此语法可能看上去像String.Format语法,但提供的值包装在DbParameter中,且生成的参数名称插入到指定{0}占位符的位置。

  1. var url = "http://blogs.msdn.com/webdev";
  2. var blogs = _context.Blog
  3. .FromSql("EXECUTE dbo.GetMostPopularBlogForUrl {0}", url)
  4. .ToList();

SQL:

  1. exec sp_executesql N'EXECUTE dbo.GetMostPopularBlogForUrl @p0
  2. ',N'@p0 nvarchar()',@p0=N'http://blogs.msdn.com/webdev'

SQL Server Profiler:


还可以构造DbParameter并将其作为参数值提供。由于使用了常规SQL参数占位符而不是字符串占位符,因此可安全地使用FromSql:

  1. var urlParams = new SqlParameter("Url", "http://blogs.msdn.com/webdev");
  2. var blogs = _context.Blog
  3. .FromSql("EXECUTE dbo.GetMostPopularBlogForUrl @Url", urlParams)
  4. .ToList();

SQL:

  1. exec sp_executesql N'EXECUTE dbo.GetMostPopularBlogForUrl @Url
  2. ',N'@Url nvarchar()',@Url=N'http://blogs.msdn.com/webdev'

SQL Server Profiler:

2.2使用LINQ编写SQL

可使用LINQ运算符在初始的原始SQL查询基础上进行组合。EF Core将其视为子查询,并在数据库中对其进行组合。下面的示例使用原始SQL查询,该查询从表值函数 (TVF) 中进行选择。然后,使用LINQ进行筛选和排序,从而对其进行组合。

  1. var searchTerm = "http://blogs.msdn.com/visualstudio";
  2. var blogs = _context.Blog
  3. .FromSql($"SELECT * FROM dbo.Blog")
  4. .Where(b => b.Url == searchTerm)
  5. .Include(c=>c.Post)
  6. .OrderByDescending(b => b.Createtime)
  7. .ToList();

SQL:

  1. exec sp_executesql N'SELECT [b].[BlogId], [b].[Createtime], [b].[Updatetime], [b].[Url]
  2. FROM (
  3. SELECT * FROM dbo.Blog
  4. ) AS [b]
  5. WHERE [b].[Url] = @__searchTerm_1
  6. ORDER BY [b].[Createtime] DESC, [b].[BlogId]',N'@__searchTerm_1 nvarchar()',@__searchTerm_1=N'http://blogs.msdn.com/visualstudio'
  7.  
  8. exec sp_executesql N'SELECT [b.Post].[PostId], [b.Post].[BlogId], [b.Post].[Content], [b.Post].[Title]
  9. FROM [Post] AS [b.Post]
  10. INNER JOIN (
  11. SELECT [b0].[BlogId], [b0].[Createtime]
  12. FROM (
  13. SELECT * FROM dbo.Blog
  14. ) AS [b0]
  15. WHERE [b0].[Url] = @__searchTerm_1
  16. ) AS [t] ON [b.Post].[BlogId] = [t].[BlogId]
  17. 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应用程序中的请求。

  1. public async Task<IActionResult> Index()
  2. {
  3. var id1 = Thread.CurrentThread.ManagedThreadId.ToString();
  4.  
  5. var blogs = await _context.Blog.ToListAsync();
  6.  
  7. var id2 = Thread.CurrentThread.ManagedThreadId.ToString();
  8.  
  9. return View(blogs);
  10. }

当我们运行以上代码时候,通过在关键字await上下文加入两段获取线程ID代码,我们会看到如下结果:

看到两段线程代码输出ID结果没有?从上图可以观察到,当我们在进入某个视图或者方法时候,执行到await某一个方法,当前线程不会一直等待下去,会立马回收到线程池,供其他地方调用!当该await方法返回数据时候,才从线程池调用空闲线程执行await方法下文余下的步骤。所以UI界面才不会进入假死状态。

参考文献:
复杂查询运算符
原生SQL查询
异步查询

(25)ASP.NET Core EF查询(复杂查询运算符、原生SQL查询、异步查询)的更多相关文章

  1. asp.net core+ef core

    asp.net core+ef core 官方的文档https://docs.asp.net/en/latest/tutorials/first-mvc-app/start-mvc.html 先来看一 ...

  2. C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制

    在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.Net Core的缓存机制. 关于.Net Core的缓存,官方有三种实现: 1.In Memory Cachi ...

  3. Asp.net Core + EF Core + Bootstrap搭建的MVC后台通用管理系统模板(跨平台版本)

    Asp.net Core + EF Core + Bootstrap搭建的MVC后台通用管理系统模板(跨平台版本) 原创 2016年07月22日 10:33:51 23125 6月随着.NET COR ...

  4. ASP.NET Core EF 查询获取导航属性值,使用Include封装

    // 引用 using Microsoft.EntityFrameworkCore; // 摘要: // Specifies related entities to include in the qu ...

  5. (24)ASP.NET Core EF查询(查询的工作原理、跟踪与非跟踪查询)

    1.查询生命周期 在进入正题时候,我们先来了解EF Core查询的生命周期. 1.1LINQ查询会由Entity Framework Core处理并生成给数据库提供程序可处理的表示形式(说白了就是生成 ...

  6. C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现

    今天做一个管理后台菜单,想着要用无限极分类,记得园子里还是什么地方见过这种写法,可今天找了半天也没找到,没办法静下心来自己写了: 首先创建节点类(我给它取名:AdminUserTree): /// & ...

  7. ASP.NET Core&EF 笔记

    首先创建Asp.net Core项目,然后通过 NuGet 安装 EntityFrameworkCore: Microsoft.EntityFrameworkCore.SqlServer Micros ...

  8. (17)ASP.NET Core EF基于数据模型创建数据库

    1.简介 使用Entity Framework Core构建执行基本数据访问的ASP.NET Core MVC应用程序.使用迁移(Migrations)基于数据模型创建数据库,你可以在Windows上 ...

  9. ASp.net Core EF ActionFilterAttribute AOP

    在项目中经常遇到一些数据的修改,很多时候业务方需要一个修改日志记录,这里我们计划用mssql数据库来存放日志记录,用EF来操作,记录日志可以用mvc的ActionFilterAttribute 来完成 ...

随机推荐

  1. MIPI CSI2-TX接口基于FPGA实现

    MIPI CSI2-TX用途: 跟海思的3559A芯片进行图像数据传输: MIPI CSI2-TX接口特性: xilinx 7系列芯片最大支持1.25Gbps: 最大支持lanes数量为4: 支持的图 ...

  2. 一篇文章教会你jQuery应用

    一 认识jQuery jQuery是JavaScript Query的缩写形式.jQuery是一款非常优秀的JavaScript库,即便是MVVM框架盛行的今天,也有超过半数的网页及应用直接或间接的使 ...

  3. OFD电子文档阅读器功能说明(采用WPF开发,永久免费)

    特别说明 ofd阅读器开发语言为c#,具有完全自主产权,没有使用第三方ofd开发包.可以根据你的需求快速定制开发.本阅读器还在开发完善阶段,如有任何问题,可以联系我QQ:13712486.博客:htt ...

  4. 爬虫 xpath

    xpath简介 1.xpath使用路径表达式在xml和html中进行导航 2.xpath包含标准函数库 3.xpath是一个w3c的标准 xpath节点关系 1.父节点 2.字节点 3.同胞节点 4. ...

  5. 微信小程序学习总结

    微信小程序开发环境安装以及相关设置配置 微信小程序前端页面书写 微信小程序前端样式WXSS书写 微信小程序中事件 微信小程序自定义组件 微信小程序发起请求 微信小程序登入流程 微信小程序路由跳转 微信 ...

  6. ride工具使用

    1.新建project,suite, testcase (1) 新建project:file->new project  ,输入工程名,选择Type选directory,选择工程存放路径,ok ...

  7. Python_散点图绘制

    为了可视化一些数据分布,需要以散点图的形式呈现 引入绘图工具 import matplotlib.pyplot as plt from matplotlib.font_manager import F ...

  8. 后门木马免杀-msfvenom和msf5(evasion)

    贴上使用笔记 不多介绍了 很简单的东西 msfvenom各平台生成木马大全: windows:msfvenom -a x86 --platform Windows -p windows/meterpr ...

  9. 爬虫4:pdf页面+pdfminer模块+demo

    本文介绍下pdf页面的爬取,需要借助pdfminer模块 demo一般流程: 1)设置url url = 'http://www.------' + '.PDF' 2)requests模块获取url ...

  10. Struts2:搭建原理

    记录下,struts2的搭建过程: 1核心jar包: struts-2.1.8\apps\struts2-blank-2.1.8.war 解压后 在struts2-blank-2.1.8\WEB-IN ...