最近在使用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. 19.Java 注解

    19.Java注解 1.Java内置注解----注解代码 @Deprecated                                    //不推荐使用的过时方法 @Deprecated ...

  2. 用python读写excel(xlrd、xlwt)

    最近需要从多个excel表里面用各种方式整理一些数据,虽然说原来用过java做这类事情,但是由于最近在学python,所以当然就决定用python尝试一下了.发现python果然简洁很多.这里简单记录 ...

  3. 【转】Android 底层开发的几点

    我干了3年Android sdk开发,觉得到了瓶劲没法更进一步,于是花了一年多点时间,大概摸到点门径.根据前辈的经验,Android底层完全入门需要两年. 先说下我的入门过程:第零步,下载源码,我下的 ...

  4. find命令与cat命令区别

    在当前目录下查找 MEMBERINTERFACE 这个字符串的文件find . -name '*'|xargs grep "MEMBERINTERFACE"find / -name ...

  5. android Studio 百度KEY获得发布版 SHA1 的方法

    看图说话 build-->Generate Signed APK... create new(看不懂单词意思的同胞可以参考这个网址http://www.cnblogs.com/why168888 ...

  6. [vue案例的知识点]todo-list

    文章的原材料来自于vue的官方示例:https://cn.vuejs.org/v2/examples/todomvc.html,我们在学习过程中,试着对其中的一些知识点进行记录: 一.浏览器数据存储, ...

  7. GRU(Gated Recurrent Unit) 更新过程推导及简单代码实现

    GRU(Gated Recurrent Unit) 更新过程推导及简单代码实现 RNN GRU matlab codes RNN网络考虑到了具有时间数列的样本数据,但是RNN仍存在着一些问题,比如随着 ...

  8. acm入门 杭电1001题 有关溢出的考虑

    最近在尝试做acm试题,刚刚是1001题就把我困住了,这是题目: Problem Description In this problem, your task is to calculate SUM( ...

  9. Java数据结构——栈的应用(以数制转换为例子)

    看一万遍,不如自己动手实践,请不要直接copy代码,先自己去理解例子实现的原理,然后试着自己动手去实践. 用Java去实现栈操作,会用到stack这个类,这类中有几个方法需要知道他们的用法  bool ...

  10. 2016 正确 sublime安装PHPcs PHPcodesniffer代码规范提示插件,修正网上部分不详细描述

    对你有助请点赞,请顶,不好请踩------送人玫瑰,手留余香!-------------------14:37 2016/3/212016 正确 sublime安装PHPcs PHPcodesniff ...