实体框架高级应用之动态过滤 EntityFramework DynamicFilters
实体框架高级应用之动态过滤 EntityFramework DynamicFilters
实体框架高级应用之动态过滤 EntityFramework DynamicFilters
我们开门见山,直奔主题。
一、EntityFramework DynamicFilters 是什么,它能做什么?
EntityFramework DynamicFilters是一个开源项目。你可以到这里去下载它的源码。顾名思义,它为我们做的事,就是帮我们动态过滤数据。为了照顾初学者,我们从头道来。
1、何为数据过滤?
数据过滤说简单点,就是去掉我们不想要的数据。SQL语句中的where从句,Linq中的where从句,还有扩展方法Where,就是完成这件光荣任务的。
2、何为动态?
动态的意思就是不死板地应用我们所写的条件,比如,我们在一个地方写了where从句,它只能用于这次查询,下次遇到相似的情况时,我们还得老老实实的写 where xxx=xxx。很长的一段时间,我们一直这样,很和谐地使用着这种方法。突然有一天,抓了抓头:如果类似的情况,能自动加上相应的过虑条件,或是应用相应的规则,该有多好?于是就有动态。当然这里的动态,只是我们面对问题的一个方面。
3、废话半天,它到底能做什么,具体点,好不?
它可以为我们创建全局的,针对实体框架查询的过虑器,这些过滤器会自动应用于每一个查询。能被用于支持多租户,软删除,等等。过滤器能通过返回布尔类型的Linq表达式来创建,同时还支持Contains()操作符(方法)。目前支持的数据库有MS SQL Server(包含 Azure),MySql,Oracle。
二、 没有它时,我们是怎么做的?
我们以软删除(不是真正意义上的删除数据,只是在相应的记录上作一个删除标识)为例。正因为数据没有被真正地删除,只是被我们用一个标识给标记起来了,那么,我们就得在每一个查询的地方加上一个条件(过滤掉标记为删除的数据),代码可能长成这样:
1 var blogs = context.BlogEntries.Where(b => b.IsDeleted == false).ToList();
上面的代码就不用多解释了,相信你能看明白。 如果是sql 语句,你可能会说,这有什么难的,我找一个地方,把所有的查询拼接上这个条件不就OK。 确实如此,但,这里只是拿这个简单的场景来作为示例,复杂的场景呢?其次,Linq表达式拼接条件 ,不是像字符串那样随心所欲,至少很大一部分人是这样,当然也包含我。每一个查询都手工加上这样的条件,不光是工作量增加了,可维护性降低了,还分散了我们的核心业务逻辑的注意力。
三、EntityFramework DynamicFilters给我们带来了改变
当然,它只是众多解决方案之一,只是作者无私的分享出来了,没把它当成宝供在自己的电脑里。 我只需要在上下文DbContext的OnModelCreating 方法中添加过滤器。代码如下:
1 protected override void OnModelCreating(DbModelBuilder modelBuilder) 2 { 3 base.OnModelCreating(modelBuilder); 4 5 //限制所有针对BlogEntry查询的过虑(只获取未删除的) 6 //这里的全局过虑,使用了委托,以便在每次需要计算值 7 //重要:如果值使用的是一个委托,请确保它在你的应用中是全局的, 8 modelBuilder.Filter("BlogEntryFilter", (BlogEntry b, bool isDeleted) => (b.IsDeleted == isDeleted), 9 () => false); 10 11 }
就这样,它就会在我们每一个关于Blog实体的查询中添加上条件(b => b.IsDeleted == false)。我们无需关心它如何添加这个条件,使用的地方,完全透明,就像没有它一样。示例代码如下:
1 /// <summary> 2 /// 查询 3 /// </summary> 4 /// <param name="context"></param> 5 /// <param name="userName"></param> 6 private static void Query(ExampleContext context, string userName) 7 { 8 var account = context.Accounts 9 .Include(a => a.BlogEntries).FirstOrDefault(a => a.UserName == userName); 13 Console.WriteLine("账号{0}的博客有:",userName); 14 if (account == null) return; 15 foreach (var blog in account.BlogEntries) 16 { 17 Console.WriteLine("{0}",blog.Id); 18 } 19 }
但需要注意的是,如果在同一个上下文DbContext实例中,运用过虑器之前,过虑器有被禁用过,而数据被缓存时,过滤器就不会起任何效果,所有使用时,你一定要避免在同一个上下文中因更改过滤器而影响结果的情况。
如果你在某种情况下不想使用过虑器时,你可以使用如下代码将其禁用:
1 //禁用过滤器 2 context.DisableFilter("BlogEntryFilter");
注意:禁用只对当前上下文DbContext实例有效,不影响别的上下文实例。如果你想对所有的上下文实例有效时,可以在 OnModelCreating方法中使用全局禁用函数:
1 //全局禁用过滤器 2 modelBuilder.DisableFilterGlobally("BlogEntryFilter");
启用的代码类似,这里就不多少了,直接看代码:
1 //启用过滤器 2 context.EnableFilter("BlogEntryFilter"); 3 context.EnableAllFilters();
说了这么多,我们来看看运用过滤器的效果吧,代码如下:
1 class Program { 2 static void Main(string[] args) { 3 4 // 过滤器默认启用 5 var context = new ExampleContext(); 6 7 Console.WriteLine(" 使用过滤器BlogEntryFilter进行查询"); 8 Query(context, "homer"); 9 10 //禁用过滤器 11 context.DisableFilter("BlogEntryFilter"); 12 13 Console.WriteLine(" 禁用过滤器BlogEntryFilter进行查询"); 14 Query(context, "homer"); 15 16 Console.ReadLine(); 17 } 18 19 /// <summary> 20 /// 查询 21 /// </summary> 22 /// <param name="context"></param> 23 /// <param name="userName"></param> 24 private static void Query(ExampleContext context, string userName) 25 { 26 var account = context.Accounts 27 .Include(a => a.BlogEntries).FirstOrDefault(a => a.UserName == userName); 28 29 Console.WriteLine("账号{0}的博客有:",userName); 30 if (account == null) return; 31 foreach (var blog in account.BlogEntries) 32 { 33 Console.WriteLine("{0}",blog.Id); 34 } 35 } 36 }
代码输出如下:
四、EntityFramework DynamicFilters原理概述
它是通过在对象 DbModelBuilder 上添加扩展方法Filter实现的,核心代码如下:
1 private static void Filter<TEntity>(DbModelBuilder modelBuilder, string filterName, LambdaExpression predicate, params object[] valueList) 2 { 3 InitializeDynamicFilters(null); 4 5 filterName = ScrubFilterName(filterName); 6 7 modelBuilder.Conventions.Add(new DynamicFilterConvention(filterName, typeof(TEntity), predicate)); 8 9 // Always add the filter to _GlobalParameterValues - need it to be able to disable it 10 _GlobalParameterValues.TryAdd(filterName, new DynamicFilterParameters()); 11 12 int numParams = predicate.Parameters == null ? 0 : predicate.Parameters.Count; 13 int numValues = valueList == null ? 0 : valueList.Length; 14 for (int i = 1; i < numParams; i++) 15 { 16 object value = ((i - 1) < numValues) ? valueList[i - 1] : null; 17 SetFilterGlobalParameterValue(null, filterName, predicate.Parameters[i].Name, value); 18 } 19 }
整个项目的源代码不多,如果你有兴趣,请阅读源代码。文中使用的代码,请于结尾处下载。
最后,我要说明的是,文中并没有把 EntityFramework DynamicFilters的方方面面说完,只是说了一些常见的场景。更多的细节,说阅读源码,或者和大家一起实践、交流。
文中示例源代码下载地址:http://files.cnblogs.com/files/VolcanoCloud/EFDynamicFilterDemo.rar
实体框架交流QQ群: 458326058,欢迎有兴趣的朋友加入一起交流
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/
实体框架高级应用之动态过滤 EntityFramework DynamicFilters相关推荐
- MVC之实体框架(数据持久化框架)EntityFrameWork(EF)
EF - EntityFrameWork 中文名:实体框架(数据持久化框架) 1.使用EF查询(Linq to EF) 1.1使用标准查询运算符来查询 OumindBlogEntities db = ...
- [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:MVC程序中实体框架的连接恢复和命令拦截...
这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第四篇:MVC程序中实体框架的连接恢复和 ...
- ADO.NET Entity Framework如何:通过每种类型一个表继承以定义模型(实体框架)
本主题介绍如何手动创建具有每种类型一个表继承层次结构的概念模型.每种类型一个表继承使用数据库中单独的表为继承层次结构中的每种类型维护非继承属性和键属性的数据. 说明: 建议使用 ADO.NET 实体数 ...
- mysql ef6 您的项目引用了最新版_您的项目引用了最新实体框架;但是,找不到数据链接所需的与版本兼容的实体框架数据库 EF6使用Mysql的技巧...
转载至: http://www.cnblogs.com/Imaigne/p/4153397.html 您的项目引用了最新实体框架:但是,找不到数据链接所需的与版本兼容的实体框架数据库 EF6使用Mys ...
- Entity Framework 实体框架的形成之旅--实体数据模型 (EDM)的处理(4)
在前面几篇关于Entity Framework 实体框架的介绍里面,已经逐步对整个框架进行了一步步的演化,以期达到统一.高效.可重用性等目的,本文继续探讨基于泛型的仓储模式实体框架方面的改进优化,使我 ...
- 使用实体框架、Dapper和Chain的仓储模式实现策略
\ 关键要点: \ Dapper这类微ORM(Micro-ORM)虽然提供了最好的性能,但也需要去做最多的工作.\ 在无需复杂对象图时,Chain这类Fluent ORM更易于使用.\ 对实体框架(E ...
- mysql数据库连接6_c# – 实体框架的动态MySQL数据库连接6
实体框架6提供了一些方便的细微变化,有助于使MySQL工作,并创建动态数据库连接. 使用Entity Framework 6获取MySQL 首先,在我回答这个问题的日期,与EF6兼容的唯一的.Net连 ...
- ADO.NET Entity Framework建模和映射(实体框架)
在实体框架中,可以采用最适合您应用程序的方式定义概念模型.存储模型以及这两种模型之间的映射.使用 Visual Studio 中的实体数据模型工具,可以从数据库或图形模型创建一个 . edmx 文件, ...
- Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)
很久没有写博客了,一些读者也经常问问一些问题,不过最近我确实也很忙,除了处理日常工作外,平常主要的时间也花在了继续研究微软的实体框架(EntityFramework)方面了.这个实体框架加入了很多特性 ...
最新文章
- java中过滤器Filter的使用总结【转载】
- lua 字符串分割_Lua 分隔字符串,可以设置指定分隔符
- vcard 2.1介绍
- Android客户端与服务器交互方式-小结
- 深度学习之循环神经网络(10)GRU简介
- mysql 8.0.22_最新版MySQL 8.0.22下载安装超详细教程(Windows 64位)
- redis实现原理和应用(redis读书笔记)
- MobileNetV3 论文
- 【spring事务管理】
- 《Presto(Trino)——The Definitive Guide》CHAPTER 6 Connectors Advanced CHAPTER 7 Connector Examples
- 我总结了五种常用聚类分析算法,推荐收藏
- 软件测试 | 测试开发 | Sikuli 基于图形识别的自动化测试技术
- 千秋华夏 壮丽河山 国庆节快乐~
- ROS2—服务(Service)
- Python 英文文本字母跳转概率统计
- html 里的文章代码
- java留言系统_JAVA留言板系统.doc
- 一键实现Windows和MacOS同屏操作,是什么神级体验?
- 计算机信息技术指哪些专业,信息技术类专业包括哪些
- 【WSL2】ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemo
热门文章
- 国内首部高尔夫商战小说《手腕》(林健锋著)
- ClewareControl 2.4 发布,传感器控制程序,增加对 python 的支持
- [跟我学UML] UML包图中的包和命名空间
- 使用visual studio code调试php代码
- CentOS7 Apache调优之开启deflate压缩模块
- Visual Studio 2017 15.7预览版发布
- 《易学Python》——1.8 总结
- C++Primer学习——函数
- [数据结构复习]树_二叉树
- LINUX下面NetworkManager和network冲突的问题