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. bootstrap-table 页脚总计(自定义统计总数)

    •首先给table添加属性: showFooter: footer js代码如下: //初始化bootstrapTableinitBootstrapTable: function () { var o ...

  2. 做高逼格程序员之说走就走的「Linux To Go 」

    简介:想拥有一个Linux,在自己的电脑上安装双系统太麻烦.想和WTG一样,随插随用. 使用LTG的好处 安装.修复系统:配置好后的Linux系统极其强大. 工作中我们同样可以使用这个系统,回到家里插 ...

  3. Cutting Sticks UVA - 10003

    题文: 见:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_proble ...

  4. PHP中sha1()函数和md5()函数的绕过

    相信大家都知道,sha1函数和md5都是哈希编码的一种,在PHP中,这两种编码是存在绕过漏洞的. PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值 ...

  5. 本人亲测-SSM整合后的基础包(供新手学习使用,可在本基础上进行二次开发)

    本案例是在eclipse上进行开发的,解压后直接添加到eclipse即可.还需要自己配置maven环境.链接:https://pan.baidu.com/s/1siuvhCJASuZG_jqY5utP ...

  6. 题解:2018级算法第二次上机 Zexal的竞赛

    题目描述: 样例: 实现解释: 一道需要一点思考的动态规划题目 知识点:动态规划,数据记录 首先将题目描述调整:分别输入不同分数的题目总分(便于后续计算),当获得了i分数的总分后无法获得i-1和i+1 ...

  7. string字符串转数组

    /** * THis_is_a_cat * This Is A Cat * * Cat A Is This * @author Administrator * */ public class Test ...

  8. ASP.NET Core API总结(一)

    ASP.NET Core API 问题:当应用收到一个http请求之后,API应用程序是怎么一步步执行的. 注册服务——构造容器——使用服务——创建对象 1.         创建一个新的API之后, ...

  9. enable_shared_from_this

    头文件<memory> enable_shared_from_this是一个模板类. 使用场景:需要把自己类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr. str ...

  10. HDU 1532 Drainage Ditches(最大流 EK算法)

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=1532 思路: 网络流最大流的入门题,直接套模板即可~ 注意坑点是:有重边!!读数据的时候要用“+=”替 ...