实战 EF(LINQ) 如何以子查询的形式来 Join
如题,大多数网上关于 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的更多相关文章
- 走向面试之数据库基础:二、SQL进阶之case、子查询、分页、join与视图
一.CASE的两种用法 1.1 等值判断->相当于switch case (1)具体用法模板: CASE expression WHEN value1 THEN returnvalue1 WHE ...
- 聊聊MySQL的子查询
1. 背景 在之前介绍MySQL执行计划的博文中已经谈及了一些关于子查询相关的执行计划与优化.本文将重点介绍MySQL中与子查询相关的内容,设计子查询优化策略,包含半连接子查询的优化与非半连接子查询的 ...
- postgresql子查询优化(提升子查询)
问题背景 在开发项目过程中,客户要求使用gbase8s数据库(基于informix),简单的分页页面响应很慢.排查发现分页sql是先查询出数据在外面套一层后再取多少条,如果去掉嵌套的一层,直接获取则很 ...
- 在MySQL中使用子查询和标量子查询的基本用法
一.MySQL 子查询 子查询是将一个 SELECT 语句的查询结果作为中间结果,供另一个 SQL 语句调用.MySQL 支持 SQL 标准要求的所有子查询格式和操作,也扩展了特有的几种特性.子查询没 ...
- MySQL数据库 crud语句 ifnull() 创建新账户 备份数据库 一对多关系 多对多(中间表) 外键约束 自关联 子查询注意事项 DML DDL DQL mysql面试题 truncate与delete的区别
DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 DDL ...
- Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等)
Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等) 子查询 描述:查询订单数超过5的顾客信息 查询句法: var 子查询 = from c i ...
- LINQ之路 7:子查询、创建策略和数据转换
在前面的系列中,我们已经讨论了LINQ简单查询的大部分特性,了解了LINQ的支持计术和语法形式.至此,我们应该可以创建出大部分相对简单的LINQ查询.在本篇中,除了对前面的知识做个简单的总结,还会介绍 ...
- Linq To Sql 语法 子查询 & In & Join
子查询 描述:查询订单数超过5的顾客信息 查询句法: var 子查询 =from cin ctx.Customers where ...
- LINQ 如何动态创建 Where 子查询
还是那句话,十年河东,十年河西,莫欺少年穷! 学无止境,精益求精... 今天探讨下如何构造动态的LINQ子查询 LINQ,相信大家都写过,很简单,下面以一个基本的范例说明下: namespace Co ...
随机推荐
- 最小生成树之Kruskal(克鲁斯卡尔)算法
学习最小生成树算法之前我们先来了解下下面这些概念: 树(Tree):如果一个无向连通图中不存在回路,则这种图称为树. 生成树 (Spanning Tree):无向连通图G的一个子图如果是一颗包含G的所 ...
- centos6.7 配置Elasticsearch
Elasticsearch(以下简称ES),是一款开源的全文搜索引擎,获得了广泛的应用.这篇博客将介绍在centos6.7上如何配置ES. 一.安装JAVA环境 centos默认安装了JAVA环境,首 ...
- 使用 shell / python 进行sql的excel报表导出
如果要求你进行一个表数据的导出,如果使用shell的话,很容易做到,即执行一下 select 语句就可以拿到返回结果了! 如下: /usr/bin/mysql -u"${username}& ...
- ansible copy 模块的使用
copy copy 模块是将 ansible 管理主机上的文件拷贝上远程主机中,与 fetch 相反,如果目标路径不存在,则自动创建,如果 src 的目录带“/” 则复制该目录下的所有东西,如果 sr ...
- javascript权威指南笔记[1-5]
1.javaScript的数据类型分为两类:原始类型和对象类型: 2.javaScript中除了数字,字符串,布尔值,null,undefined之外就是对象了: 3.对象(object)是属性(pr ...
- 每日分享!介绍Css 盒模型!
如何定义盒模型: 在CSS盒子模型理论中,页面中所有的元素都是看成一个盒子,并且还占据一定的空间. 一个页面是由很多这样的盒子组成的.这些盒子之间都会相会影响,因此我们掌握CSS盒模型相当重要.需要理 ...
- MySQL视图简介与操作
1.准备工作 在MySQL数据库中创建两张表balance(余额表)和customer(客户表)并插入数据. create table customer( id int(10) primary key ...
- 带你找到五一最省的旅游路线【dijkstra算法代码实现】
算法推导过程参见[dijkstra算法推导详解] 此文为[dijkstra算法代码实现] https://www.cnblogs.com/Halburt/p/10767389.html package ...
- RabbitMQ消息队列(一)-RabbitMQ的优劣势及产生背景
本篇并没有直接讲到技术,例如没有先写个Helloword.我想在选择了解或者学习一门技术之前先要明白为什么要现在这个技术而不是其他的,以免到最后发现自己学错了.同时如果已经确定就是他,最好先要了解下技 ...
- RDIFramework.NET V3.3 Web版角色授权管理新增角色对操作权限项、模块起止生效日期的设置
在实际应用在我们可能会有这样的需求,某个操作权限项(按钮)或菜单在某个时间范围内可以让指定角色访问.此时通过我们的角色权限扩展设置就可以办到. 在我们框架V3.3 Web版本全新增加了角色权限扩展设置 ...