本文首先介绍了ABP内置的软删除过滤器(ISoftDelete)和多租户过滤器(IMultiTenant),然后介绍了如何实现一个自定义过滤器,最后介绍了在软件开发过程中遇到的实际问题,同时给出了解决问题的一个未必最优的思路。

一.预定义过滤器

  ABP中的数据过滤器源码在Volo.Abp.Data[2]包中,官方定义了2个开箱即用的过滤器,分别是软删除过滤器(ISoftDelete)和多租户过滤器(IMultiTenant),想必大家对这2个内置的过滤器已经比较熟悉了。下面重点说下通过IDataFilter实现局部过滤,和通过AbpDataFilterOptions实现全局过滤。

1.IDataFilter局部过滤

  主要的思路就是通过IDataFilter依赖注入,然后通过_dataFilter.Disable<XXX>()临时的启用或者禁用过滤器:

namespace Acme.BookStore
{public class MyBookService : ITransientDependency{private readonly IDataFilter _dataFilter;private readonly IRepository<Book, Guid> _bookRepository;public MyBookService(IDataFilter dataFilter, IRepository<Book, Guid> bookRepository){_dataFilter = dataFilter;_bookRepository = bookRepository;}public async Task<List<Book>> GetAllBooksIncludingDeletedAsync(){// 临时禁用ISoftDelete过滤器using (_dataFilter.Disable<ISoftDelete>()){return await _bookRepository.GetListAsync();}}}
}

这样就会局部地把IsDeleted=1的记录查找出来。

2.AbpDataFilterOptions全局过滤

主要是通过选项(Options)的方式来配置全局过滤:

Configure<AbpDataFilterOptions>(options =>
{options.DefaultStates[typeof(ISoftDelete)] = new DataFilterState(isEnabled: false);
});

这样就会全局地把IsDeleted=1的记录查找出来。其中的一个问题是,这段代码写到哪里呢?自己是写到XXX.Host->XXXHostModule->ConfigureServices中,比如Business.Host->BusinessHostModule->ConfigureServices。

二.自定义过滤器

  自定义过滤器是比较简单的,基本上都是八股文格式了,对于EFCore来说,就是重写DbContext中的ShouldFilterEntity和CreateFilterExpression方法。因为暂时用不到MongoDB,所以不做介绍,有兴趣可以参考[1],也不是很难。下面通过一个例子来介绍下EF Core的自定义过滤器。

1.定义过滤器接口

首先定义一个过滤器接口,然后实现该接口:

public interface IIsActive
{bool IsActive { get; }
}public class Book : AggregateRoot<Guid>, IIsActive
{public string Name { get; set; }public bool IsActive { get; set; } //Defined by IIsActive
}

2.重写DbContext中的方法

然后就是重写DbContext中的ShouldFilterEntity和CreateFilterExpression方法:

protected bool IsActiveFilterEnabled => DataFilter?.IsEnabled<IIsActive>() ?? false;protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
{if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))){return true;}return base.ShouldFilterEntity<TEntity>(entityType);
}protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
{var expression = base.CreateFilterExpression<TEntity>();if (typeof(IIsActive).IsAssignableFrom(typeof(TEntity))){Expression<Func<TEntity, bool>> isActiveFilter = e => !IsActiveFilterEnabled || EF.Property<bool>(e, "IsActive");expression = expression == null ? isActiveFilter : CombineExpressions(expression, isActiveFilter);}return expression;
}

  突然看上去觉得这个自定义过滤器好复杂,后来想想那ABP内置的软删除过滤器(ISoftDelete)和多租户过滤器(IMultiTenant)是如何实现的呢?然后就找到了源码ABP/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs

看了源码实现后会发现格式一模一样,所以自定义过滤器使用起来没有这么复杂。

三.遇到的实际问题

  假如在SaaS系统中,有一个主中心和分中心的概念,什么意思呢?就是在主中心中可以看到所有分中心的User数据,同时主中心可以把一些通用的资料(比如,科普文章)共享给分中心。在ABP群里问了下,有人建议宿主就是宿主,用来做租户管理的,不能把它当成一个租户,这是一个父子租户的问题。有人建议搞一个仿租户ID过滤器,这样既能曲线解决问题,又不背离宿主和租户的原则。父子租户第一次听说,所以暂不考虑。因为系统已经开发了一部分,如果每个实体都继承仿租户ID过滤器接口,那么也觉得麻烦。
  最终选择把主中心当成是宿主用户,分中心当成是租户。对于一些通用的资料(比如,科普文章),在增删改查中直接IDataFilter局部过滤。比如查找实现如下:

public async Task<PagedResultDto<ArticleDto>> GetAll(GetArticleInputDto input)
{// 临时禁用掉IMultiTenant过滤器using (_dataFilter.Disable<IMultiTenant>()){var query = (await _repository.GetQueryableAsync()).WhereIf(!string.IsNullOrWhiteSpace(input.Filter), a => a.Title.Contains(input.Filter));var totalCount = await query.CountAsync();var items = await query.OrderBy(input.Sorting ?? "Id").Skip(input.SkipCount).Take(input.MaxResultCount).ToListAsync();var dto = ObjectMapper.Map<List<Article>, List<ArticleDto>>(items);return new PagedResultDto<ArticleDto>(totalCount, dto);}
}

  对于"主中心中可以看到所有分中心的User数据"这个问题,因为只是涉及到查看,不做增删改,所以又新建了一个User查找接口,在该接口中直接IDataFilter局部过滤。这样新建的User查找接口就可以看到所有分中心的数据,原来的User查找接口仅能看到宿主或者租户的User数据。总之,适合自己需求的架构就是最好的,如果架构满足不了需求了,那么就迭代架构。

参考文献:
[1]数据过滤:https://docs.abp.io/zh-Hans/abp/6.0/Data-Filtering
[2]Volo.Abp.Data:https://github.com/abpframework/abp/tree/dev/framework/src/Volo.Abp.Data
[3]EntityFramework.DynamicFilters:https://github.com/zzzprojects/EntityFramework.DynamicFilters
[4]ABP文档笔记 - 数据过滤:https://www.cnblogs.com/wj033/p/6494879.html
[5]ABP领域层 - 数据过滤器:https://www.kancloud.cn/gaotang/abp/225839
[6]Mastering-ABP-Framework:https://github.com/PacktPublishing/Mastering-ABP-Framework
[7]ABP多租户:https://docs.abp.io/zh-Hans/abp/6.0/Multi-Tenancy
[8]ASP.NET Boilerplate中文文档:https://www.kancloud.cn/gaotang/abp/225819
[9]详解ABP框架中数据过滤器与数据传输对象使用:https://wenku.baidu.com/view/ec237e90b3717fd5360cba1aa8114431b80d8e5e
[10]ASP.NET Boilerplate官方文档:https://aspnetboilerplate.com/Pages/Documents/Introduction
[11]How to create a custom data filter with EF Core:https://support.aspnetzero.com/QA/Questions/4752/How-to-create-a-custom-data-filter-with-EF-Core

ABP中的数据过滤器相关推荐

  1. ABP理论学习之数据过滤器

    本篇目录 介绍 预定义过滤器 关闭过滤器 开启过滤器 设置过滤器参数 定义自定义过滤器 其他ORM 介绍 软删除模式通常用于不会真正从数据库删除一个实体而是仅仅将它标记为"已删除的" ...

  2. abp过滤规则android,ABP的数据过滤器(Data Filters)

    我们在数据库开发中,一般会运用软删除 (soft delete)模式 ,即不直接从数据库删除数据 ,而是标记这笔数据为已删除.因此 ,如果实体被软删除了,那么它就应该不会在应用程序中被检索到.要达到这 ...

  3. ABP vNext详细教程——数据过滤器

    目录 简介 基础用法 2.使用 3.查询拼装 4.​​​​​​​禁用 5.​​​​​​​补充说明 源码解析 1.DataFilter 2.AbpDbContext 简介 数据过滤器是ABP vNext ...

  4. EF Core 中实现 动态数据过滤器

    前言 在项目开发中,我们很多时候都会设计  软删除.所属用户 等等一系列字段 来方便我们在业务查询的时候进行各种过滤 然后引申的问题就是: 在业务查询的时候,我们要如何加上这些条件?或者动态禁用某些查 ...

  5. mysql中如何设置过滤器_mysql 如何动态修改复制过滤器

    MySQL动态修改复制过滤器 说说今天遇到的问题吧,今天在处理一个业务方的需求,比较变态,我大概描述一下: 1.线上的阿里云rds上面有个游戏的日志库,里面的表都是日表的形式,数据量比较大了,每次备份 ...

  6. mysql中如何设置过滤器_mysql – 使用计数器实现过滤器

    我想要实现的目标: 我正在开发带有产品目录的网站. 这是与我的问题相关的实体的规范化模型(简化): 因此存在一些产品特征(如本例中的大小和类型),它们都具有预定义的值集(例如,存在大小1,2和3,类型 ...

  7. 拆分命令_在MongoDB分片集群中拆分数据块chunks

    MongoDB Manual (Version 4.2)> Sharding > Data Partitioning with Chunks > Split Chunks in a ...

  8. 十步优化SQL Server中的数据访问

    故事开篇:你和你的团队经过不懈努力,终于使网站成功上线,刚开始时,注册用户较少,网站性能表现不错,但随着注册用户的增多,访问速度开始变慢,一些用户开始发来邮件表示抗议,事情变得越来越糟,为了留住用户, ...

  9. hbase中为何不能向表中插入数据_Hbase快速入门(超精炼总结)

    基本概念: HBase是列簇式Key-Value存储系统,构建在HDFS之上的.支持随机插入和删除. 总结Hbase的架构核心,就两个字"有序" . 磁盘的读写,随机与顺序,相差3 ...

最新文章

  1. linux 增量备份镜像,【备份与恢复】合并增量备份与映像副本
  2. boost::fusion::erase_key用法的测试程序
  3. HDU - 2438 Turn the corner(三分)
  4. 表示深深的感谢飞鸽传书源码
  5. C#LeetCode刷题之#21-合并两个有序链表(Merge Two Sorted Lists)
  6. 到底图啥?百度工程师非法控制155台服务器“挖矿”,被判刑3年
  7. Android XML中引用自定义内部类view的四个why
  8. 【前端 · 面试 】JavaScript 之你不一定会的基础题(二)
  9. HDU2011 多项式求和【入门】
  10. python安装csv出错_python处理csv文件问题解决贴
  11. 从源码的角度分析ViewGruop的事件分发
  12. 自偏置电流镜设计实例
  13. 初来乍到,多多关照!
  14. 控件中一些常用的属性和事件
  15. 2019届高三理科数学选择填空整理
  16. 网格建模资源管理(第一次翻译老外的东西,嘿嘿!)
  17. 简单表单提交php教程,php教程之表单提交实例
  18. IT界的兄弟姐妹们,大家好。
  19. linux 动态库 软链接,Linux操作系统下动态库的生成及链接方法
  20. C语言·XDOJ练习·股票计算

热门文章

  1. [原创]Java Web——外卖配送系统/在线点餐系统
  2. Deep learning for arts——王乃岩(图森科技)
  3. 即将发布的 Apache Spark 3.2 将内置 Pandas API
  4. 微信推出史上最简单「拍一拍」新功能,仅需一行代码,好友们都玩疯了!
  5. Java 开发规范文档
  6. ros建图过程中给上位机发布地图信息
  7. IntelliJ IDEA 还能画思维导图,果然最强 IDE!
  8. 小爱音箱 电脑 麦克风_颜值音质皆出色,还有丰富功能,小米小爱音箱体验
  9. 【2020年高被引学者】 杨笛一 佐治亚理工大学
  10. 牛牛找工作--网易2019实习生招聘编程题