如题,大多数网上关于 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. vue.js window.removeEventListener 移除

    vue项目中的小坑记录下,想要移除window的addEventListener,需要把后面的function挂在到this上,removeEventListener 和 addEventListen ...

  2. 【视频】ASP.NET Core MVC 2.* 入门

    比较初级的入门教程,网址在B站:https://www.bilibili.com/video/av33728783/ 内容如下: 1. ASP.NET Core 简介和开发工具 2. ASP.NET ...

  3. JSP 内置对象(上)

    JSP 内置对象是 Web 容器创建的一组对象,不使用 new 关键字就可以直接使用的对象.如上一章中使用脚本实现打印九九乘法表中的out对象 <%-- 脚本:out对象是JSPWriter类的 ...

  4. 内核mailbox

    只罗列增加取走消息: static int add_to_rbuf(struct mbox_chan *chan, void *mssg) { int idx; unsigned long flags ...

  5. C#语法——元组类型

     元组Tuple   我们现在使用的C#语法已经可以满足日常的开发需求,但C#语法还在进行版本的更新,在创造更多更优秀的语义来让我们使用.这里介绍一下C#5.0里的提供的语法——元组. 在C#中定义T ...

  6. Java设计模式系列-装饰器模式

    原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...

  7. Ext JS中的typeOf

    Ext JS中的typeOf:以字符串格式,返回给定变量的类型 其中对字符串对象.元素节点.文本节点.空白文本节点判断并不准确 测试代码如下: <!DOCTYPE HTML PUBLIC &qu ...

  8. Vue开发插件

    (一)Vue.js的插件应该有一个公开方法:install. 这个方法的第一个参数是Vue构造器,第二个参数是一个可选的选项对象,一般是如下操作: MyPlugin.install = functio ...

  9. 洛谷P2664 树上游戏(点分治)

    题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...

  10. [目录]C#学习笔记

    C#是微软.NET平台下最重要的编程语言,它与C.C++不同,C#编写的源程序是托管在.NET平台下的.C#源程序经C#编译器编译成中间语言(IL,Intermediate Language),再经C ...