如题,大多数网上关于 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之自动化在虚拟机部署操作系统并自带python环境

    (1)使用详情: **************************** *    操作说明     * **************************** 1.修改Config文件夹中的Se ...

  2. 【STM32H7教程】第3章 STM32H7整体把控

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第3章   STM32H7整体把控 初学STM32H7一 ...

  3. InkImageDataSetGenerator-开源一个可用于机器学习的书写轨迹图片生成的小工具

    这是一个简单易用的图片数据集生成小工具,基于OpenCV和UWP Ink API,它可以根据指定的手写轨迹生成一系列各个角度的图片.每张图片的尺寸和总体数量都是可以指定的,均存放在统一的生成目录中.h ...

  4. python接口自动化(十)--post请求四种传送正文方式(详解)

    简介 post请求我在python接口自动化(八)--发送post请求的接口(详解)已经讲过一部分了,主要是发送一些较长的数据,还有就是数据比较安全等.我们要知道post请求四种传送正文方式首先需要先 ...

  5. 快速新建简单的koa2后端服务

    既然前端工程化是基于NodeJS,那么选择NodeJs做前后端分离部署也是理所应当的.其实只需要实现静态资源和代理的话,用nginx才是最好的选择,用NodeJS是为了日后能进一步在服务端上实现自动构 ...

  6. Fiddler使用~知多少?

    昨天已经说了Fiddler的原理,那么今天就说说它是如何使用.我们进入正题. 在大多数网站测试的情况下,我们执行检测一个端口号或网址,这种场景一定会出现,记住,是一定会. 那么就需要我们过滤了,我们需 ...

  7. Linux下PAM模块学习总结

    在Linux中执行有些程序时,这些程序在执行前首先要对启动它的用户进行认证,符合一定的要求之后才允许执行,例如login, su等.在Linux中进行身份或是状态的验证程序是由PAM来进行的,PAM( ...

  8. Java基础系列-二进制操作

    原创文章,转载请标注出处:<Java基础系列-二进制操作> 概述 Java源码中涉及到大量的二进制操作,非常的复杂,但非常的快速. Java二进制表示法 首先了解下二进制,二进制是相对十进 ...

  9. 【带着canvas去流浪】(2)绘制折线图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 3.1 一般折线图 3.2 用贝塞尔曲线绘制平滑折线图 四. 大数据量场景 示例代码托管在:https://github.com/dashnowo ...

  10. 上传图片截图预览控件不显示cropper.js 跨域问题

    上传图片到图片服务器,因为域名不同,多以会有跨域问题. No 'Access-Control-Allow-Origin' header is present on the requested reso ...