最近在使用EF进行联合查询过程中,遇到了一件不开心的事情。

已禁用懒加载

var post = await _repository.GetMyPostById(blogId, postId).AsNoTracking()
.Include(p => p.PostToCategories)
.SingleOrDefaultAsync();
如上代码所示的查询中,使用Include()关联了PostToCategories,这是常用的联合查询方式。可是PostToCategories是软删除(IsAcitve)的,使用Include()方法会把所有的相关的PostToCategories都查询出来,这不是我们想要的结果。
首先分析下原因,Include()方法,是根据配置的关系查询关联的对象,所以我们只要在它生成sql之前加上过滤条件就可以了,可是纵观EF的api,无一能实现目的。既然这样,我们只能想想其他办法了。
var post = await _repository.GetMyPostById(blogId, postId).AsNoTracking()
.Select( p => new {
BlogPost = p,
PostToCategories = p.PostToCategories.Where(c => c.IsActive)
}).SingleOrDefaultAsync();
var blogPost = post.BlogPost;
blogPost.PostToCategories = post.PostToCategories.ToList();
用匿名类型接受主表和从表的查询结果,这样就可以为从表设置过滤条件了。最后,把匿名结果显示赋值给blogPost。
通过观察生成的sql语句,我们发现确实是在 ` join PostToCategories ` 后面增加了where条件。
但是这种方法在面对多对多关系时,就**不够优雅**了。
 var post = await _repository.GetMyPostById(blogId, postId).AsNoTracking()
.Include(p => p.TagMap)
.Include(p => p.TagMap.Select(t => t.Tag))
.SingleOrDefaultAsync();

改写成如下:

var post = await _repository.GetMyPostById(blogId, postId).AsNoTracking()
.Select( p => new {
BlogPost = p,
TagMap = p.TagMap,
Tag = p.TagMap.Select(t => t.Tag),
}).SingleOrDefaultAsync();
var blogPost = post.BlogPost;
blogPost.TagMap = post.TagMap;
blogPost.TagMap.ForEach(m => m.Tag = post.Tag.FirstOrDefault(g => g.Id == m.TagId));

是不是感觉不美好了?

那有没有更好的办法呢?stackoverflow上有人推荐了一个针对EF的扩展包 EntityFramework.DynamicFilters ,它的实现方式是在OnModelCreating的时候给Entity设置好过滤条件,当前DbContext对象涉及到该Entity类型的查询时,都会自动加上过滤条件。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Filter("PostToCategory_IsActive", (PostToCategory ptc) => ptc.IsActive, true);//为PostToCategory类型设置过滤条件:IsActive==true
}

直接使用Include()就可以得到我们想要的结果,如下所示:

var post = await _repository.GetMyPostById(blogId, postId).AsNoTracking()
.Include(p => p.PostToCategories)
.SingleOrDefaultAsync();

可是这样以来所有的涉及到PostToCategories的查询都会被过滤,怎么办呢?EntityFramework.DynamicFilters提供 禁用/启动 过滤条件的API

context.DisableFilter/EnableFilter("PostToCategory_IsActive");// 在当前DbContext实例对象中禁用/启用名为PostToCategory_IsActive的Filter

modelBuilder.DisableFilterGlobally("PostToCategory_IsActive");// 全局禁用名为PostToCategory_IsActive的Filter

context.DisableAllFilters();//禁用所有的Filters

context.EnableAllFilters(); //启用所有的Filters

于是代码就变成了这样:

一、设置Filter

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Filter("PostToCategory_IsActive", (PostToCategory ptc) => ptc.IsActive, true);//为PostToCategory类型设置过滤条件:IsActive==true
}

二、全局禁用Filters

context.DisableAllFilters();

三、在需要过滤的地方启用Filter

context.EnableFilter("PostToCategory_IsActive");
var post = await _repository.GetMyPostById(blogId, postId).AsNoTracking()
.Include(p => p.PostToCategories)
.SingleOrDefaultAsync();

而且还没有考虑DbContext缓存查询结果带来的问题。

如果说第一种解决方案不优雅,那么这种方案就是恶心

--- 2016.10.10 ---

昨天借鉴了ABP的封装思想,把EntityFramework.DynamicFilters的API封装了下,确实美观多了。

参见:

本来顺风顺水,如tkb至简的博文中描述的那样,优雅的过滤数据,可惜最后在一次保存的时候出现了意外,最后发现原因出在和EntityFramework.Extended有冲突,因为后者是重新生成了SqlExpression,没有对EntityFramework.DynamicFilters在设置where条件中的@DynamicFilterParam_000001赋值。

暂时没有想到更好的办法,遂先滚回去。:(

EF联合查询,如何设置条件过滤从表数据的更多相关文章

  1. EF联合查询的新用法

    用EF很多年了,做联合查询时,只知道linq和lambda两种语法,今天朋友发了一个链接,打开看后发现是EF内置的新的关于联合查询的方法,赶紧抄录下来,以备后用. 现在先把这几种方法,各写一个例子,便 ...

  2. Left Join on 多条件查询时,条件过滤的问题

    例如:A  Left Join B on (...) on 后面的条件是对B数据的过滤,如果要对A的数据或者联合之后的数据集进行过滤,则要把过滤条件放在where子句中

  3. EF 联合查询

    EF 文章表和标签表联合查询标签id在dis中的文章,还不知道性能如何 var query = tagRepo.Entities.Include("Tags").Where(t = ...

  4. LINQ,EF联合查询join

    public object GetListAdmin() { //return db_C56.Admins //   .Where(a => a.Status != "D") ...

  5. SQL Server -- 回忆笔记(二):增删改查,修改表结构,约束,关键字使用,函数,多表联合查询

    SQL Server知识点回忆篇(二):增删改查,修改表结构,约束,关键字使用,函数,多表联合查询 1. insert 如果sql server设置的排序规则不是简体中文,必须在简体中文字符串前加N, ...

  6. SharePoint 列表多表联合查询

    在SharePoint平台二次开发中,我们有时需要涉及多表关联查询展示多列表中的不同字段信息:SharePoint和Sql数据表一样,也支持多表联合查询,但是不像Sql语句那样简单,有一定的局限性,需 ...

  7. mysql之连接查询、联合查询、子查询

    本文内容: 连接查询 联合查询 子查询 from子查询 where子查询 exists子查询 首发日期:2018-04-11 连接查询: 连接查询就是将多个表联合起来查询,连接查询方式有内连接.外连接 ...

  8. MyBatis 多表联合查询及优化 以及自定义返回结果集

    下面就来说一下 mybatis 是通过什么来实现多表联合查询的.首先看一下表关系,如图: 这 里,我已经搭好了开发的环境,用到的是 SpringMVC + Spring + MyBatis,当然,为了 ...

  9. baby sqli 联合查询加入数据 手工注入

    0x00 BabySQli 原题目描述:刚学完sqli,我才知道万能口令这么危险,还好我进行了防护,还用md5哈希了密码! 登陆页面,查看源码后点进search.php看到一段可疑的句子MMZFM42 ...

随机推荐

  1. NOIP主要考查范围

    基本数据结构 栈 队列 数组 优先队列 中级数据结构 堆(大根堆,小根堆) 并查集和带权并查集 哈希表 高级数据结构 (可选学) 树状数组 线段树 各种其他树 字符串和相关内容 1.KMP 2.各种操 ...

  2. jQuery获取输入框并设置焦点

    $(':input:enabled:visible:first').focus(); $("input:text:visible:first").focus(); 表单元素选择器: ...

  3. [MS SQL Server]SQL Server如何开启远程访问

    在日常工作中,经常需要连接到远程的MS SQL Server数据库中.当然也经常会出现下面的连接错误. 解决方法: 1. 设置数据库允许远程连接,数据库实例名-->右键--->属性---C ...

  4. Git - 问题集

    1.If no other git process is currently running, this probably means a git process crashed in this re ...

  5. OpenLayers 3 之 地图样式(ol.style)详解

    地图样式是由 style 类控制的,其包含了地图样式的方方面面,例如,填充色.图标样式.图片样式.规则图形样式.边界样式.文字样式等,样式一般针对矢量要素图层. 矢量图层样式可以事先写好,写成静态的, ...

  6. DFS序+线段树 hihoCoder 1381 Little Y's Tree(树的连通块的直径和)

    题目链接 #1381 : Little Y's Tree 时间限制:24000ms 单点时限:4000ms 内存限制:512MB 描述 小Y有一棵n个节点的树,每条边都有正的边权. 小J有q个询问,每 ...

  7. Oracle 查询出来的数据取第一条

    Oracle 查询出来的数据取第一条 --------------------------------------------------------------------------- 转载自:h ...

  8. js和css文件压缩

    压缩网址 http://tool.chinaz.com/tools/jscodeconfusion.aspx http://tool.oschina.net/jscompress?type=3 htt ...

  9. 浅谈我对 jQuery 的了解

    总述 0 获取 jQuery 对象 1 对象跳转 2 方法调用 3 常用API 4 $(…); 5 jQuery 对象获取 6 Data 相关方法 7 选择器 8 基本的过滤器 9 内容过滤选择器 1 ...

  10. asp.net两种方式的短信接口使用(提供接口的都是收费的)

    一种是http请求的方式,另一种就是提供WebService接口供调用的. //服务商 sms.webchinese.cn //sms_url="http://sms.webchinese. ...