如题,大多数网上关于 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

    public class PersonQueryCondition
{
public IEnumerable<string> CityNameList { get; set; }
}

PersonService.cs

    public class PersonService : IPersonService
{
private readonly IRepository<Person> _personRepository;
private readonly IRepository<City> _cityRepository; public PersonService(IRepository<Person> personRepository,
IRepository<City> cityRepository
)
{
this._personRepository = personRepository;
this._cityRepository = cityRepository;
} /// <summary>
/// 根据城市名称列表获取分页实体
/// </summary>
/// <param name="cityIdList"></param>
/// <returns></returns>
public List<Person> GetPagedList(PersonQueryCondition queryCondition, int pageIndex, int pageSize, out int recordCount)
{
return this._personRepository.GetListPagedByCondition<PersonQueryCondition>(c => c.Id > ,
CombineQuery,
queryCondition,
pageIndex,
pageSize,
out recordCount);
} protected virtual IQueryable<Person> CombineQuery(IQueryable<Person> query, PersonQueryCondition queryCondition)
{
if (queryCondition == null)
{
return query;
}
if (queryCondition.CityNameList != null && queryCondition.CityNameList.Any())
{
query = query.Join(_cityRepository.Table, p => p.CityID, c => c.Id, (p, c) => new { Person = p, City = c })
.Where(a => queryCondition.CityNameList.Contains(a.City.Name))
.Select(c => c.Person)
.Distinct();
}
return query;
}
}

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

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

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

基类方法如下:

4. 生成 的SQL 语句

SQL 语句如下:

SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[CityID] AS [CityID]
FROM
[dbo].[Person] AS [Extent1]
INNER JOIN [dbo].[City] AS [Extent2] ON [Extent1].[CityID] = [Extent2].[Id]
WHERE
(
[Extent1].[Id] > 0
)
AND
(
[Extent2].[Name] IN (N'深圳', N'北京')
)
AND
(
[Extent2].[Name] IS NOT NULL
)

谢谢浏览!

实战 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 2016-Powershell新建用户补充

    前边我们介绍到Windows Server 2016-图形化新建域用户(一) 及 Windows Server 2016-批量新建域用户(二) ,里边提到了批量通过new-aduser常见帐号,这里简 ...

  2. July 05th. 2018, Week 27th. Thursday

    Pleasure in the job puts perfection in the work. 乐于工作才能有完美表现. From Aristole. Do you want promotion? ...

  3. Storm入门(十一)Twitter Storm源代码分析之CoordinatedBolt

    作者: xumingming | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://xumingming.sinaapp.com/811/twitter-stor ...

  4. [LeetCode] 26. 删除排序数组中的重复项

    题目链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ 题目描述: 给定一个排序数组,你需要在原地删除重复 ...

  5. 详解k8s原生的集群监控方案(Heapster+InfluxDB+Grafana) - kubernetes

    1.浅析监控方案 heapster是一个监控计算.存储.网络等集群资源的工具,以k8s内置的cAdvisor作为数据源收集集群信息,并汇总出有价值的性能数据(Metrics):cpu.内存.netwo ...

  6. Git分布式版本控制器安装注意点及其常用命令

    将git按照默认选项下载安装后,打开git bach版面进行git命令行操作(记住在安装的过程中文件夹中不能存在中文):注:Windows下,路径名不要包含中文,因为Git对中文支持不给力,可能会存在 ...

  7. PHP全栈学习笔记8

    面向对象的基本概念,面向对象编程,oop,面向对象,面向对象的分析,面向对象的设计,面向对象的编程,什么是类. 类,属性和方法,类,对象,面向对象编程的三大特点.特点,封装性,继承性,多态性. 封装性 ...

  8. [Swift]动态变化顶部状态栏(statusBar)的颜色

    顶部状态栏(statusBar)的两种样式: (1).default 样式:黑色. (2).light 样式:白色 一.无导航栏情况 如果没有使用导航控制器 UINavigationControlle ...

  9. java基础(十八)----- java动态代理原理源码解析

    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 静态代理 1.静态代理 静态代理:由程序员创建或特定工 ...

  10. EF Core利用Scaffold从根据数据库生成代码

    在EF6 之前的时代,如果需要从数据库中生成代码,是可以直接在界面上操作的,而到了EF Core的时代,操作方式又有更简便的方式了,我们只需要记住以下这条指令. Scaffold-DbContext ...