最近在使用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. PHP函数、数组

    PHP函数 PHP的真正威力源自于它的函数函数是通过调用函数来执行的,可以在页面的任何位置调用函数 PHP函数准则:函数名称以字母或下划线开头(不能以数字开头)函数的名称应该提示出它的功能 四要素:返 ...

  2. json相关,浏览器打开json格式的api接口时,进行格式化,chrome插件

    在chrome浏览器中安装Google jsonview插件能够自动格式化json格式的数据.

  3. java.lang.IllegalStateException: Web app root system property already set to different value

    webAppRootKey是在java web项目的web.xml配置文件中表示项目的唯一标示,在Eclipse调试Web项目时,项目的路径是一个临时路径,不在真正的路径下,可以通过log4j日志的方 ...

  4. ajax删除DB数据

    1.前台js $().ready(function () { $('[name="checkAll"]').click(function () { if ("checke ...

  5. java中注解的使用与实例(一)

    注解目前非常的流行,很多主流框架都支持注解,而且自己编写代码的时候也会尽量的去用注解,一时方便,而是代码更加简洁. 注解的语法比较简单,除了@符号的使用之外,它基本与Java固有语法一致.Java S ...

  6. A*算法的原理 <转>

    第一部分:A*算法简介    写这篇文章的初衷是应一个网友的要求,当然我也发现现在有关人工智能的中文站点实在太少,我在这里 抛砖引玉,希望大家都来热心的参与.     还是说正题,我先拿A*算法开刀, ...

  7. node.js之开发环境搭建

    一.安装linux系统 (已安装linux可跳此步骤) 虚拟机推荐选择:VirtualBox 或者 Vmware (专业版永久激活码:5A02H-AU243-TZJ49-GTC7K-3C61N) 我这 ...

  8. 【虚拟机】oracle Virtual Box4.2.6虚拟机正在运行的过程中删除了其上的一个备份,之后虚拟机就无法使用了

    原因未知,解决方法没有,网上也没有找到相关的解决方法.偶然的操作导致

  9. U-Boot Driver Model领域模型设计

    需求分析 在2014年以前,uboot没有一种类似于linux kernel的设备驱动模型,随着uboot支持的设备越来越多,其一直受到如下问题困扰: 设备初始化流程都独立实现,而且为了集成到系统,需 ...

  10. C# 中对 ArrayList 的排序

    ArrayList 元素 //目录条目类 public class FolderItem { public string filename; public string filetype; publi ...