前几次,我们从说明文档,示例,单元测试了解了怎么用这个动态过滤器,那么如果仅仅是为了实现目的,知道怎么用就可以完成相应的功能开发,但我还想了解的问题是

  1. 作者是怎么将动态过滤器与EF结合的
  2. 有哪些设计思想在里面
  3. 为什么这样设计
  4. 这个设计是最好的么,其他框架是怎么做的
  5. 这样做有什么优点和缺点
  6. 我可以从里面学习到什么思想和技术

    首先,让我们抛开这个小扩展,回到ado.net时代,假如数据库里面有如下几个表:

我想实现假删除功能,删除People表里面id=11的

update people set IsDeleted=1 where ID=11

删除完之后,查询没有被删除的数据

正常情况下,那个假删除的数据对于用户来说就是真删除,只是库里面还有

如果是调用者最终控制查询语句,那他要手动过滤掉假删除的数据数据

select * from People where IsDeleted!=1

那用户写语句的时候,不会去考虑你这个数据是不是假删除的,对于他来说,就是没有

这个时候,他只需要写select * from People 就应该查询出来

可实际上 ,查询出来的是

查询的时候,自然不能查询出来已经删除的数据,应该过滤掉

用户去做这件事的时候,每个语句都要处理手动加上过滤条件,当用户站到业务层去实现业务的时候,他还要考滤数据层的问题,怎么将用户的业务与数据层的关联给解耦

用户不去做这件,又要实现这样的功能,就是用户在业务层发出了查询

select * from People 的命令 然后系统自动查询出来如下正确的结果

那就需要系统去动态处理,将原来的select * from People 转换成

select * from People where IsDeleted!=1 加上过滤假删除的条件

这只是动态过滤场景里面的一种场景,如果系统里面只是有一个这样的,我们手动也可以很快搞定。当系统里面有很多类似但不同的场景,比如saas多租户,我想查询出来系统里面

当前登录租户的所有数据,但是对于登录者来说并没有租户的概念,这个系统好像就他自己在用 这个时候,我们也在针对不同的场景去做设置,那么要是有100种不同场景,1000种

是不是我们都去一个个的去做呢?

他里面是不是有相似可以提取的,如果老板突然哪天说系统不要用假删除了,太占数据库空间,那原来做的设置要怎么快速的去掉呢?

用户面向的都是对象,就算让用户设置也不能让用户去写一大推的sql语句吧,那要是数据库不切换还好,要是sql换oracle 再换成mysql 是不是每次都要改语句呢,每次改的内容是不是差别不大,相似不小,不改又运行不了?

怎么解决这些一系列问题,EntityFramework.DynamicFilters 源码里面都给出了自己的答案

要解决的问题,如过滤器要

  1. 动态可插拔
  2. 跨数据库
  3. 满足用户的不同场景
  4. 容易扩展,实现定制化开发
  5. ……

EntityFramework.DynamicFilters.通过DynamicFilterExtensions 提供对外的过滤器构建方法,方法都是通过对象扩展到EF框架里面的DbModelBuilder modelBuilder 对象上,

调用的时候,通过扩展方法,可以方便的实现过滤器的禁用,启用,创建

支持各种场景,具体的使用方式参考单元测试

动态禁用和启用

modelBuilder.DisableFilterGlobally("BlogEntryFilter")禁用过滤器

modelBuilder.EnableFilter(dbContext,filterName);启用过滤器

过滤器 modelBuilder.Filter("IsDeleted", (ISoftDelete d) => d.IsDeleted, false);

通过LambdaToDbExpressionVisitor 将定义过滤器传过来的表达式((ISoftDelete d) => d.IsDeleted, false)转换成数据库表达式

通过命令截断器,拦截将要执行到数据库的语句,加上由用户创建的过滤器,由LambdaToDbExpressionVisitor转换过来的DbExpression,形成最终的语句,对于用户来说屏蔽掉自己手动添加语句的细节

对于不满足我们的要求的可以扩展System.Data.Entity.Infrastructure.Interception

//

// 摘要:

//     An object that implements this interface can be registered with System.Data.Entity.Infrastructure.Interception.DbInterception

//     to receive notifications when Entity Framework executes commands.

//

// 备注:

//     Interceptors can also be registered in the config file of the application. See

//     http://go.microsoft.com/fwlink/?LinkId=260883 for more information about Entity

//     Framework configuration.

public interface IDbCommandInterceptor : IdbInterceptor

命令截断器接口,实现自己的拦截方式

然后在InitializeDynamicFilters(this DbContext context)

调用拦截器集合,自己的拦截器加入进去就可以实现自己的定制化

Rafy 框架假删除插件也是通过拦截器实现的如下:

StampSubmitInterceptor 实现抽象拦截器SubmitInterceptor

在插件初始化的时候,将自定义插件添加到集合里面

当前拦截器,执行完之后,调用下一个拦截器

link.InvokeNext(this, e);

通过rafy的删除插件,与EntityFramework.DynamicFilters 过滤器的对比都是通过命令截断器实现

Rafy的命令截断器是作者自定义的SubmitInterceptor

EntityFramework.DynamicFilters实现的是EF自己的IdbCommandInterceptor

读EntityFramework.DynamicFilters源码_心得_设计思想_04的更多相关文章

  1. 读EntityFramework.DynamicFilters源码_心得_整体了解01

    前两天同事发给我一个连接地址:实体框架高级应用之动态过滤 EntityFramework DynamicFilters为什么会找到动态过滤的内容,是源于前段时间,我们想做一个个人blog 后端用.NE ...

  2. 读EntityFramework.DynamicFilters源码_心得_单元测试03

    上个星期我们只是显示了一个示例,怎么在EF的框架内,注入我们拓展的动态过滤器 第一步:安装EntityFramework.DynamicFilters 第二步:重写OnModelCreating方法 ...

  3. 读EntityFramework.DynamicFilters源码_心得_示例演示02

    上次对EntityFramework.DynamicFilters整体的项目结构有了一个认识,这次我们就通过阅读说明文档,示例项目,和单元测试,来动手构建一个我们的体验项目,通过对动态过滤器的使用,使 ...

  4. 源码解读Dubbo分层设计思想

    一.Dubbo分层整体设计概述 我们先从下图开始简单介绍Dubbo分层设计概念: (引用自Duboo开发指南-框架设计文档) 如图描述Dubbo实现的RPC整体分10层:service.config. ...

  5. Zookeeper_阅读源码第一步_在 IDE 里启动 zkServer(集群版)

    上篇文章Zookeeper_阅读源码第一步_在 IDE 里启动 zkServer(单机版)讲了在 idea 里以单机的方式启动zookeeper,这篇介绍一下以集群的方式启动. 集群方式启动,才会真正 ...

  6. Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库

    http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...

  7. Java并发指南10:Java 读写锁 ReentrantReadWriteLock 源码分析

    Java 读写锁 ReentrantReadWriteLock 源码分析 转自:https://www.javadoop.com/post/reentrant-read-write-lock#toc5 ...

  8. 如何读懂Framework源码?如何从应用深入到Framework?

    如何读懂Framework源码? 首先,我也是一个应用层开发者,我想大部分有"如何读懂Framework源码?"这个疑问的,应该大都是应用层开发. 那对于我们来讲,读源码最大的问题 ...

  9. 读源码【读mybatis的源码的思路】

    ✿ 需要掌握的编译器知识 ★ 编译器为eclipse为例子 调试准备工作(步骤:Window -> Show View ->...): □ 打开调试断点Breakpoint: □ 打开变量 ...

随机推荐

  1. 微信小程序之tabbar切卡

    最近在研究小程序的时候,遇到了一个问题,就是tabbar切卡,在android上有fragment,在RN上也有提供一个第三方的组件来用,微信小程序,好像没有专门的一个组件来实现这个功能,度娘了大半天 ...

  2. NTP搭建指南

    NTP搭建指南 前言: NTP是网络时间协议(Network Time Protocol),用于全球的标准时间(UTC)的校正. 一般NTP 服务有不同的层次:一层是源头NTP 服务器,一层服务器都设 ...

  3. ThinkPHP 3.2.x 集成极光推送指北

    3.2版本已经过了维护生命周期,官方已经不再维护,请及时更新至5.0版本 -- ThinkPHP 官方仓库 以上,如果有条件,请关闭这个页面,然后升级至 ThinkPHP 5,如果由于各种各样的原因无 ...

  4. 条目二十八《正确理解由reverse_iterator的base()成员函数所产生的iterator的用法》

    条目二十八<正确理解由reverse_iterator的base()成员函数所产生的iterator的用法> 迭代器的种类一共有四种,上面已经说过了.这里就不再次写出来. 这一个条目主要是 ...

  5. python简介和环境搭建

    简介: python 是一种解释型.面向对象编程语言   由 Guido van Rossum 于1989年底发明, 第一个公开发行版发行于1991年, 最初被设计用于编写自动化脚本(shell)  ...

  6. 容器化VS微服务

    1 微服务 1.1 思想 开发人员自己测试.部署和运维自己编写的代码,即自己负责构建生命周期的全部. 1.2 Spring Boot 提供服务化的能力,即把容器.服务所需依赖和服务一起打包成一个jar ...

  7. ubuntu->错误

    1.dpkg *** locked 原因:安装某个包不成功, 可以使用命令 dpkg --configure -a 来重启中断的安装过程 如果屡次安装不成功放弃安装,则删除 lock 2.flashp ...

  8. Bootrap 项目实战(微金所前端首页)第三部分(CSS,js源码)

    CSS源码 common.css /** *Created by xxc on 2019/2/26 */ body, html, div, img, a, p, ul, ol, dl, dd, dt, ...

  9. linux 系统管理(三) 系统信息查看 inx

    inxi infomation x i (信息每个人都爱) Inxi 最初是为控制台和 IRC(网络中继聊天)开发的一个强大且优秀的命令行系统信息脚本.可以使用它获取用户的硬件和系统信息,它也用于调试 ...

  10. MSSQL远程连接操作(转)

    --遠程連接操作 /****************************************************************************************** ...