• 读EntityFramework.DynamicFilters源码_心得_设计思想_04


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

    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

  • 相关阅读:
    JVM(java 虚拟机)内存设置
    elasticsearch 安装和 基本操作命令
    Spring
    springmvc 文件上传和拦截器
    InitBinder和数据校验
    异常、类型转换
    git 提交方式
    Springmvc(二)
    Springmvc(一)
    SSM
  • 原文地址:https://www.cnblogs.com/gdnyfcuso/p/6563549.html
Copyright © 2020-2023  润新知