如题,大多数网上关于 LINQ Join 的示例都是以 from x in TableA  join ... 这样的形式,这种有好处,也有劣势,就是在比如我们使用的框架如果已经封装了很多方法,比如分页方法。而我们的业务方法只需要在 Service 层调用框架的分页方法,同时注入条件拼接的委托就可以了。而这时候,为了简单,就会以调用 Join() 方法来实现关联查询,外部看起来好像是子查询,而实际上 Entity Framework 生成 SQL 时,还是会以 Inner join 的形式来生成 SQL 语句,但不管怎样,我们还是解决了我们的实际需求,也就可以说成功了。

1. 数据库

假设有 2 张表。Person 表和 City 表。Person 表的 CityID 关联 City 表的 ID。

City 表:

Person 表:

2. 需求

现在,前台界面有一个 checkbox 复选框组,列出所有的城市,然后用户可以选择一个或多个,比如“深圳”和“北京”,分页列出对应的人员。注意,前台界面只需要列出 Person 的 Id 和 Name 就可以了,不需要列出城市的名称。

3. 代码

PersonQueryCondition.cs

  1. public class PersonQueryCondition
  2. {
  3. public IEnumerable<string> CityNameList { get; set; }
  4. }

PersonService.cs

  1. public class PersonService : IPersonService
  2. {
  3. private readonly IRepository<Person> _personRepository;
  4. private readonly IRepository<City> _cityRepository;
  5.  
  6. public PersonService(IRepository<Person> personRepository,
  7. IRepository<City> cityRepository
  8. )
  9. {
  10. this._personRepository = personRepository;
  11. this._cityRepository = cityRepository;
  12. }
  13.  
  14. /// <summary>
  15. /// 根据城市名称列表获取分页实体
  16. /// </summary>
  17. /// <param name="cityIdList"></param>
  18. /// <returns></returns>
  19. public List<Person> GetPagedList(PersonQueryCondition queryCondition, int pageIndex, int pageSize, out int recordCount)
  20. {
  21. return this._personRepository.GetListPagedByCondition<PersonQueryCondition>(c => c.Id > ,
  22. CombineQuery,
  23. queryCondition,
  24. pageIndex,
  25. pageSize,
  26. out recordCount);
  27. }
  28.  
  29. protected virtual IQueryable<Person> CombineQuery(IQueryable<Person> query, PersonQueryCondition queryCondition)
  30. {
  31. if (queryCondition == null)
  32. {
  33. return query;
  34. }
  35. if (queryCondition.CityNameList != null && queryCondition.CityNameList.Any())
  36. {
  37. query = query.Join(_cityRepository.Table, p => p.CityID, c => c.Id, (p, c) => new { Person = p, City = c })
  38. .Where(a => queryCondition.CityNameList.Contains(a.City.Name))
  39. .Select(c => c.Person)
  40. .Distinct();
  41. }
  42. return query;
  43. }
  44. }

请注意:如果 Person 和 City 是多对多的关系,即一个用户可以在多个城市生活,一个城市也可以有多个用户。那么如果要筛选即在 “深圳” 生活的人,又曾经在 “北京” 生活过的人,则 LINQ 的语句需要更改为:

  1. if (queryCondition.CityNameList != null && queryCondition.CityNameList.Any())
  2. {
  3. //这里需要循环嵌套 Join 来实现
  4. foreach (string cityNameItem in queryCondition.CityNameList)
  5. {
  6. query = query.Join(_cityRepository.Table, p => p.CityID, c => c.Id, (p, c) => new { Person = p, City = c })
  7. .Where(a => a.City.Name == cityNameItem) // 注意:这里不再是调用 .Contains 方法,而是直接等于判断。
  8. .Select(c => c.Person)
  9. .Distinct();
  10. }
  11. }
  12. return query;

代码解释截图如下(注意:.Select(c => c.Person) 后必须加一个 Distinct(),因为可能包含重复元素。):

基类方法如下:

4. 生成 的SQL 语句

SQL 语句如下:

  1. SELECT
  2. [Extent1].[Id] AS [Id],
  3. [Extent1].[Name] AS [Name],
  4. [Extent1].[CityID] AS [CityID]
  5. FROM
  6. [dbo].[Person] AS [Extent1]
  7. INNER JOIN [dbo].[City] AS [Extent2] ON [Extent1].[CityID] = [Extent2].[Id]
  8. WHERE
  9. (
  10. [Extent1].[Id] > 0
  11. )
  12. AND
  13. (
  14. [Extent2].[Name] IN (N'深圳', N'北京')
  15. )
  16. AND
  17. (
  18. [Extent2].[Name] IS NOT NULL
  19. )

谢谢浏览!

实战 EF(LINQ) 如何以子查询的形式来 Join的更多相关文章

  1. 走向面试之数据库基础:二、SQL进阶之case、子查询、分页、join与视图

    一.CASE的两种用法 1.1 等值判断->相当于switch case (1)具体用法模板: CASE expression WHEN value1 THEN returnvalue1 WHE ...

  2. 聊聊MySQL的子查询

    1. 背景 在之前介绍MySQL执行计划的博文中已经谈及了一些关于子查询相关的执行计划与优化.本文将重点介绍MySQL中与子查询相关的内容,设计子查询优化策略,包含半连接子查询的优化与非半连接子查询的 ...

  3. postgresql子查询优化(提升子查询)

    问题背景 在开发项目过程中,客户要求使用gbase8s数据库(基于informix),简单的分页页面响应很慢.排查发现分页sql是先查询出数据在外面套一层后再取多少条,如果去掉嵌套的一层,直接获取则很 ...

  4. 在MySQL中使用子查询和标量子查询的基本用法

    一.MySQL 子查询 子查询是将一个 SELECT 语句的查询结果作为中间结果,供另一个 SQL 语句调用.MySQL 支持 SQL 标准要求的所有子查询格式和操作,也扩展了特有的几种特性.子查询没 ...

  5. MySQL数据库 crud语句 ifnull() 创建新账户 备份数据库 一对多关系 多对多(中间表) 外键约束 自关联 子查询注意事项 DML DDL DQL mysql面试题 truncate与delete的区别

    DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 DDL ...

  6. Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等)

    Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等) 子查询 描述:查询订单数超过5的顾客信息 查询句法: var 子查询 = from c i ...

  7. LINQ之路 7:子查询、创建策略和数据转换

    在前面的系列中,我们已经讨论了LINQ简单查询的大部分特性,了解了LINQ的支持计术和语法形式.至此,我们应该可以创建出大部分相对简单的LINQ查询.在本篇中,除了对前面的知识做个简单的总结,还会介绍 ...

  8. Linq To Sql 语法 子查询 & In & Join

    子查询 描述:查询订单数超过5的顾客信息 查询句法: var 子查询 =from cin ctx.Customers                    where                  ...

  9. LINQ 如何动态创建 Where 子查询

    还是那句话,十年河东,十年河西,莫欺少年穷! 学无止境,精益求精... 今天探讨下如何构造动态的LINQ子查询 LINQ,相信大家都写过,很简单,下面以一个基本的范例说明下: namespace Co ...

随机推荐

  1. windows server 2008 R2 Enterprise 系统安全配置

    window 安全配置规则 一.开启防火墙 二.允许远程网络进行远程桌面连接 如果使用默认的远程端口的话,按照下图,允许远程桌面通过防火墙就行了: 如果你的远程端口号不是默认的,则需要按照(四)中新建 ...

  2. spring 【二】学习之spring EL

    spring EL-spring 表达式语言,支持在xml和注解的形式,类似于JSP的el表达式的形式. 其主要使用@Value注解的结构形式 其主要功能 [1].注入普通字符串 [2].注入操作系统 ...

  3. IIS Express 配置缓存位置

    Please refer to the three configure files to check if they contains the rule setting. "%Program ...

  4. C#运算符的简单使用测试

    在代码中看到的代码中|=,有点不太理解故重新学习了下位运算符. 位运算符在 c# 中的测试用例 [TestMethod] public void TestMethod1() { var a = fal ...

  5. Jvm启动,关闭及对应钩子

    很多时候应用服务启动或关闭会做一些预加载(比如缓存,定时任务启动等)或收尾处理工作(比如程序失败记录等) 1. 首先看下Spring框架服务启动加载操作实现,直接上代码 继承实现接口Applicati ...

  6. 49个Spring经典面试题总结,附带答案,赶紧收藏

    1. 一般问题 1.1. 不同版本的 Spring Framework 有哪些主要功能? Version Feature Spring 2.5 发布于 2007 年.这是第一个支持注解的版本. Spr ...

  7. Javascript高级编程学习笔记(95)—— WebGL(1) 类型化数组

    WebGL webgl 是针对 canvas 的 3D上下文,与其它Web技术不同,WebGL并非是W3C制定的标准,而是由 Khronos Group 制定的. 类型化数组 WebGL所涉及的复杂运 ...

  8. Python后台开发Django( 模板 与 值匹配 )

    模板文件(templates) 在setting.py中,设置模板存放位置 在APP中view的使用 from django.shortcuts import render #导入 def homex ...

  9. springcloud之自定义简易消费服务组件

    本次和大家分享的是怎么来消费服务,上篇文章讲了使用Feign来消费,本篇来使用rest+ribbon消费服务,并且通过轮询方式来自定义了个简易消费组件,本文分享的宗旨是:自定义消费服务的思路:思路如果 ...

  10. Python爬虫入门教程 50-100 Python3爬虫爬取VIP视频-Python爬虫6操作

    爬虫背景 原计划继续写一下关于手机APP的爬虫,结果发现夜神模拟器总是卡死,比较懒,不想找原因了,哈哈,所以接着写后面的博客了,从50篇开始要写几篇python爬虫的骚操作,也就是用Python3通过 ...