EF联合查询,如何设置条件过滤从表数据
最近在使用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联合查询,如何设置条件过滤从表数据的更多相关文章
- EF联合查询的新用法
用EF很多年了,做联合查询时,只知道linq和lambda两种语法,今天朋友发了一个链接,打开看后发现是EF内置的新的关于联合查询的方法,赶紧抄录下来,以备后用. 现在先把这几种方法,各写一个例子,便 ...
- Left Join on 多条件查询时,条件过滤的问题
例如:A Left Join B on (...) on 后面的条件是对B数据的过滤,如果要对A的数据或者联合之后的数据集进行过滤,则要把过滤条件放在where子句中
- EF 联合查询
EF 文章表和标签表联合查询标签id在dis中的文章,还不知道性能如何 var query = tagRepo.Entities.Include("Tags").Where(t = ...
- LINQ,EF联合查询join
public object GetListAdmin() { //return db_C56.Admins // .Where(a => a.Status != "D") ...
- SQL Server -- 回忆笔记(二):增删改查,修改表结构,约束,关键字使用,函数,多表联合查询
SQL Server知识点回忆篇(二):增删改查,修改表结构,约束,关键字使用,函数,多表联合查询 1. insert 如果sql server设置的排序规则不是简体中文,必须在简体中文字符串前加N, ...
- SharePoint 列表多表联合查询
在SharePoint平台二次开发中,我们有时需要涉及多表关联查询展示多列表中的不同字段信息:SharePoint和Sql数据表一样,也支持多表联合查询,但是不像Sql语句那样简单,有一定的局限性,需 ...
- mysql之连接查询、联合查询、子查询
本文内容: 连接查询 联合查询 子查询 from子查询 where子查询 exists子查询 首发日期:2018-04-11 连接查询: 连接查询就是将多个表联合起来查询,连接查询方式有内连接.外连接 ...
- MyBatis 多表联合查询及优化 以及自定义返回结果集
下面就来说一下 mybatis 是通过什么来实现多表联合查询的.首先看一下表关系,如图: 这 里,我已经搭好了开发的环境,用到的是 SpringMVC + Spring + MyBatis,当然,为了 ...
- baby sqli 联合查询加入数据 手工注入
0x00 BabySQli 原题目描述:刚学完sqli,我才知道万能口令这么危险,还好我进行了防护,还用md5哈希了密码! 登陆页面,查看源码后点进search.php看到一段可疑的句子MMZFM42 ...
随机推荐
- 19.Java 注解
19.Java注解 1.Java内置注解----注解代码 @Deprecated //不推荐使用的过时方法 @Deprecated ...
- 用python读写excel(xlrd、xlwt)
最近需要从多个excel表里面用各种方式整理一些数据,虽然说原来用过java做这类事情,但是由于最近在学python,所以当然就决定用python尝试一下了.发现python果然简洁很多.这里简单记录 ...
- 【转】Android 底层开发的几点
我干了3年Android sdk开发,觉得到了瓶劲没法更进一步,于是花了一年多点时间,大概摸到点门径.根据前辈的经验,Android底层完全入门需要两年. 先说下我的入门过程:第零步,下载源码,我下的 ...
- find命令与cat命令区别
在当前目录下查找 MEMBERINTERFACE 这个字符串的文件find . -name '*'|xargs grep "MEMBERINTERFACE"find / -name ...
- android Studio 百度KEY获得发布版 SHA1 的方法
看图说话 build-->Generate Signed APK... create new(看不懂单词意思的同胞可以参考这个网址http://www.cnblogs.com/why168888 ...
- [vue案例的知识点]todo-list
文章的原材料来自于vue的官方示例:https://cn.vuejs.org/v2/examples/todomvc.html,我们在学习过程中,试着对其中的一些知识点进行记录: 一.浏览器数据存储, ...
- GRU(Gated Recurrent Unit) 更新过程推导及简单代码实现
GRU(Gated Recurrent Unit) 更新过程推导及简单代码实现 RNN GRU matlab codes RNN网络考虑到了具有时间数列的样本数据,但是RNN仍存在着一些问题,比如随着 ...
- acm入门 杭电1001题 有关溢出的考虑
最近在尝试做acm试题,刚刚是1001题就把我困住了,这是题目: Problem Description In this problem, your task is to calculate SUM( ...
- Java数据结构——栈的应用(以数制转换为例子)
看一万遍,不如自己动手实践,请不要直接copy代码,先自己去理解例子实现的原理,然后试着自己动手去实践. 用Java去实现栈操作,会用到stack这个类,这类中有几个方法需要知道他们的用法 bool ...
- 2016 正确 sublime安装PHPcs PHPcodesniffer代码规范提示插件,修正网上部分不详细描述
对你有助请点赞,请顶,不好请踩------送人玫瑰,手留余香!-------------------14:37 2016/3/212016 正确 sublime安装PHPcs PHPcodesniff ...