ABP官方文档翻译 3.8 数据过滤器
数据过滤器
介绍
软删除模式是常用的模式,这种模式并没有从数据库中删除实体而是打上'deleted'的标记。所以,如果实体被软删除,那么它不应该被意外的提取到应用中。为了保证这种事情不会发生,当我们选择实体时,应该添加入‘IsDeleted=false’这样的SQL where条件。这是一个乏味、易忘但很重要的工作。所以,应该由自动的方式来完成。
ABP提供了数据过滤器,可以用来基于一些规则自动过滤查询。这有一些预定义的过滤器,也可以创建自己的过滤器。
预定义过滤器
ISoftDelete
Sofe-delete过滤器用来当查询数据库时自动过滤(从结果中提取)已删除的实体。如果一个实体为软删除模式的,它必须实现ISoftDelete接口,这个接口只有IsDeleted属性。示例:
public class Person : Entity, ISoftDelete
{
public virtual string Name { get; set; } public virtual bool IsDeleted { get; set; }
}
Person实体不会真正从数据库中删除,而是当需要删除它时,将IsDeleted属性设置为true。当使用IRepository.Delete方法(你可以手动设置IsDeleted为true,但是Delete方法是更自然、更好的方式)时,ABP自动完成这个操作。
实现ISoftDelete接口后,当你从数据库获取People的列表时,已删除的people不会被提取。这里有一个使用person仓储类获取所有people的示例类:
public class MyService
{
private readonly IRepository<Person> _personRepository; public MyService(IRepository<Person> personRepository)
{
_personRepository = personRepository;
} public List<Person> GetPeople()
{
return _personRepository.GetAllList();
}
}
GetPeople方法仅获取Isdeleted=false(没有删除)的person实体。所有的仓储方法和导航属性都可以正常工作。我们可以添加一些其他的Where条件。它会自动添加IsDeleted=false条件到生成的查询语句中。
何时使用?
ISoftDelete过滤器除非显示的禁用它,否则它总是启用的。
边注:如果你实现了IDeletionAudited(它扩展了ISoftDelete)接口,ABP会自动设置删除时间和删除用户id。
IMustHaveTenant
如果你创建了多租户的应用,并把所有的租户数据都存放在一个数据库中,你肯定不想一个租户可以看到其他租户的数据。在这种情况下,你可以实现IMustHaveTenant接口。示例:
public class Product : Entity, IMustHaveTenant
{
public int TenantId { get; set; } public string Name { get; set; }
}
IMustHaveTenant定义了TenantId用来区分不用租户的实体。ABP默认使用IAbpSession获取当前租户的TenantId,并自动为当前租户过滤查询。
何时使用?
IMustHaveTenant默认是启用的。
如果当前用户没有登录到系统或者当前用户是一个租主用户(租户用户是超级用户,可以管理租户和租户数据),ABP自动禁用IMustHaveTenant过滤器。因此,所有租户的所有数据都被提取到应用中。注意这个和安全无关,你应该总是授权敏感的数据。
IMayHaveTenant
如果实体被租户和租主共享(这意味着一个实体对象可能被一个租户拥有,也可能是租主)。你可以使用IMayHaveTenant过滤器。IMayHaveTenant接口定义了TenantId,但它是nullable。
public class Role : Entity, IMayHaveTenant
{
public int? TenantId { get; set; } public string RoleName { get; set; }
}
null值意味着是一个租主实体,非null值以为了这个实体数据租户且租户id为TenantId。ABP默认使用IAbpSession获取当前租户的Id。IMayHaveTenant接口不如IMustHaveTenant常见。但是当需要被租户和租主同时使用数据时,你就会需要它。
何时使用
IMayHaveTenant总是可用的,除非你显示的禁用它。
禁用过滤器
你可以通过调用DisableFilter方法为每个工作单元禁用过滤器,如下所示:
var people1 = _personRepository.GetAllList(); using (_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete))
{
var people2 = _personRepository.GetAllList();
} var people3 = _personRepository.GetAllList();
DisableFilter方法使用一个或多个过滤器的名字作为参数字符串。AbpDataFilters.SoftDelete是一个常量字符串,它包含了ABP标准软删除过滤器的名字。
people2将包含删除的people,但people1和people3只有未删除的people。使用using语句,你可以在一个范围内禁用过滤器。如果你不使用using语句,过滤器将禁用到当前工作单元的结尾或者你重新显示的启用它。
你可以注入IUnitOfWorkManager并如在本例中那样使用。你也可以使用CurrentUnitOfWork属性作为捷径,如果你的类集成了一些特殊的基类(如ApplicationService、AbpController、AbpApiController...)。
关于using语句
当你使用using语句调用DisableFilter方法时,如果这时过滤器可用的,那么调用方法之后过滤器是禁用的,using语句之后会自动重新启用过滤器。但是,如果在using语句之前过滤器已经是禁用的,那么DisableFilter方法实际上什么也没做,using语句之后过滤器仍然保持禁用。
关于多租户
你可以禁用租户过滤器来查询所有租户的数据。但是记住,这种方法只对单数据库方式有效。如果每一个租户都有单独的数据库,禁用过滤器将不会查询所有租户的所有数据,因为他们在不同的数据库中,甚至在不同的服务器上。参见多租户文档了解更多信息。
全局禁用过滤器
如果需要,可以全局禁用预定义的过滤器。例如,全局禁用软删除过滤器,在你模块的PreInitialize方法中添加下面的代码:
Configuration.UnitOfWork.OverrideFilter(AbpDataFilters.SoftDelete, false);
启用过滤器
你可以在工作单元里使用EnableFilter方法来启用过滤器,和DisableFilter相似(功能相反)。EnableFilter方法返回disposable用来在using语句中使用,如果需要,可以自动重新禁用过滤器。
设置过滤器参数
过滤器可以是参数化的。IMustHaveTenant过滤器就是这种类型的一个示例,因为当前租户id是在运行时决定的。对于这种过滤器,如果需要的话我们可以改变过滤器的值,例如:
CurrentUnitOfWork.SetFilterParameter("PersonFilter", "personId", );
另一个示例:设置IMayHaveTenant过滤器的tenantId值:
urrentUnitOfWork.SetFilterParameter(AbpDataFilters.MayHaveTenant, AbpDataFilters.Parameters.TenantId, );
SetFilterParameter方法也返回一个IDisposable接口。所以,我们可以使用using语句自动重建之前的值,在using语句之后。
SetTenantId方法
当你使用SetFilterParameter方法改变MayHaveTenant和MustHaveTenant过滤器的值时,这有一个更好的方式更改租户过滤器:SetTenantId()。SetTenantId为这两个过滤器更改参数值,并且对单数据库和每个租户一个数据库两种类型都有效。所以,建议使用SetTenantId改变租户过滤器的参数值。参见多租户文档了解更多信息。
ORM集成
预定义过滤器对NHibernate、EntityFramework 6.x和Entity Framework Core同样有效。目前,你只能为Entity Framework 6.x定义自定义过滤器。
Entity Framework
对Entity Framework集成,使用EntityFramework.DynamicFilters类库实现自动数据过滤。
为了为Entity Framework创建一个自定义过滤器并集成到ABP,首先我们应该定义一个接口,它将被使用这个过滤器的实体实现。假定,我们想自动通过PersonId过滤实体。示例接口:
public interface IHasPerson
{
int PersonId { get; set; }
}
然后我们可以为需要的实体实现这个接口。示例实体如下:
public class Phone : Entity, IHasPerson
{
[ForeignKey("PersonId")]
public virtual Person Person { get; set; }
public virtual int PersonId { get; set; } public virtual string Number { get; set; }
}
我们使用它的规则定义过滤器。在我们的DbContext类,我们重写OnModelCreating并定义过滤器,如下:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder); modelBuilder.Filter("PersonFilter", (IHasPerson entity, int personId) => entity.PersonId == personId, );
}
“PersonFilter”是过滤器唯一的名称。第二个参数定义了过滤器接口和personId过滤器参数(如果过滤器没有参数可以不需要),最后的参数是personId的默认值。
最后一件事情,我们必须在模块的PreInitialize方法中注册这个过滤器到ABP的工作单元系统中。
Configuration.UnitOfWork.RegisterFilter("PersonFilter", false);
第一个参数是和我们之前定义的同样的名字。第二个参数标示这个过滤器默认是启用还是禁用。声明这么一个参数化过滤器之后,我们可以在运行时提供给他参数值并使用它。
using (CurrentUnitOfWork.EnableFilter("PersonFilter"))
{
using(CurrentUnitOfWork.SetFilterParameter("PersonFilter", "personId", ))
{
var phones = _phoneRepository.GetAllList();
//...
}
}
我们可以从一些源获取到personId而不是静态编码。上面的例子是参数化过滤器的。过滤器可以没有或有更多的参数。如果没有参数就不需要设置过滤器参数值。如果默认是启用的就不需要手动启用它(当然,我们可以禁用它)。
EntityFramework.DynaamicFilters文档
更过关于动态数据过滤器的信息,参见github页上的文档:https://github.com/jcachat/EntityFramework.DynamicFilters
我们可以为安全、激活/失活实体等等创建自定义过滤器。
其他ORMs
对于Entity Framework Core和NHibernate,数据过滤是在仓储级别实现的。这就意味着,它只有当你通过仓储查询时才会过滤。如果你直接使用DbContext(对于 EF Core)或通过自定义SQL,你需要自己处理过滤。
Configuration.UnitOfWork.OverrideFilter(AbpDataFilters.SoftDelete, false); 返回主目录
ABP官方文档翻译 3.8 数据过滤器的更多相关文章
- ABP官方文档翻译 1.1 介绍
介绍 介绍 快速示例 其他 启动模板 如何使用 介绍 我们通常会根据不同的需求来创建不同的应用程序.但是对于一些通用相似的结构总是一遍又一遍的实现,至少在某种程度上是这样的.常见的通用模块如授权.验证 ...
- ABP官方文档翻译 1.5 多租户
多租户 什么是多租户? 数据库和部署架构 多部署-多数据库 单部署-多数据库 单部署-单数据库 单部署-混合数据库 多部署-单/多/混合数据库 ABP的多租户 启用多租户 租主和租户 会话 决定当前租 ...
- ABP官方文档翻译 9.3 NHibernate集成
NHibernate集成 Nuget包 配置 实体映射 仓储 默认实现 自定义仓储 应用程序特定基础仓储类 ABP可以使用任何ORM框架,它内置集成NHibernate.此文档将讲解ABP如何使用NH ...
- ABP官方文档翻译 9.2 Entity Framework Core
Entity Framework Core 介绍 DbContext 配置 在Startup类中 在模块PreInitialize方法中 仓储 默认仓储 自定义仓储 应用程序特定基础仓储类 自定义仓储 ...
- ABP官方文档翻译 9.1 EntityFramework集成
EntityFramework集成 Nuget包 DbContext 仓储 默认仓储 自定义仓储 应用特定的基础仓储类 自定义仓储示例 仓储最佳实践 事务管理 数据存储 ABP可以使用ORM框架,它内 ...
- ABP官方文档翻译 3.5 规约
规约 介绍 示例 创建规范类 使用仓储规约 组合规约 讨论 什么时候使用? 什么时候不使用? 介绍 规约模式是一种特别的软件设计模式,通过使用布尔逻辑将业务规则链接起来重新调配业务规则.(维基百科). ...
- ABP官方文档翻译 2.5 设置管理
设置管理 介绍 关于 ISettingStore 定义设置 设置范围 重写设置定义 获取设置值 服务端 客户端 更改设置 关于缓存 介绍 每个应用都需要存储设置,并且在应用的某些地方需要使用这些设置. ...
- ABP官方文档翻译 10.1 ABP Nuget包
ABP Nuget包 Packages Abp Abp.AspNetCore Abp.Web.Common Abp.Web Abp.Web.Mvc Abp.Web.Api Abp.Web.Api.OD ...
- ABP官方文档翻译 8.1 通知系统
通知系统 介绍 发送模型 通知类型 通知数据 通知严重性 关于通知持久化 订阅通知 发布通知 用户通知管理 实时通知 客户端 通知存储 通知定义 介绍 在系统中通知用来基于特定的事件告知用户.ABP提 ...
随机推荐
- 让两个数x,y一直保持互质的模版
int gcd(int x,int y) { )return x; else return gcd(y,x%y); }
- 喵哈哈村的魔法考试 Round #1 (Div.2) 题解&源码(A.水+暴力,B.dp+栈)
A.喵哈哈村的魔法石 发布时间: 2017年2月21日 20:05 最后更新: 2017年2月21日 20:06 时间限制: 1000ms 内存限制: 128M 描述 传说喵哈哈村有三种神 ...
- Codeforces Round #412 (rated, Div. 2, base on VK Cup 2017 Round 3)(A.B.C,3道暴力题,C可二分求解)
A. Is it rated? time limit per test:2 seconds memory limit per test:256 megabytes input:standard inp ...
- COGS 2482. Franky的胡子【二分,高精度】
2482. Franky的胡子 ☆ 输入文件:beard.in 输出文件:beard.out 简单对比 时间限制:1 s 内存限制:128 MB [题目描述] Franky很苦恼他一直 ...
- poj_3070Fibonacci(矩阵快速幂)
Fibonacci Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12732 Accepted: 9060 Descri ...
- Matrix Chain Multiplication(表达式求值用栈操作)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1082 Matrix Chain Multiplication Time Limit: 2000/100 ...
- flume1.8 开发指南学习感悟
概述: Apache Flume是一个分布式.可用的系统,用于从许多不同的sources有效的收集并移动大量日志数据用于集中存储数据. 架构及数据流动模型: flume实际上就是一个Agent.Age ...
- 【程序员的吃鸡大法】利用OCR文字识别+百度算法搜索,玩转冲顶大会、百万英雄、芝士超人等答题赢奖金游戏
[先上一张效果图]: 一.原理: 其实原理很简单: 1.手机投屏到电脑: 2.截取投屏画面的题目部分,进行识别,得到题目和三个答案: 3.将答案按照一定的算法,进行搜索,得出推荐答案: 4.添加了一些 ...
- YUI 的模块信息配置优先级关系梳理
背景 YUI的配置参数较多, 可以在好几个地方配置一个module的相关信息, 如: //在全局配置, 所以YUI实例共享 YUI_config = { modules: { 'w-autcomple ...
- dede首页调用分类信息
格兰斯-与你共同开创门窗定制5G时代 5G战略--明确的,没有歧义的明亮奥尼克斯的观点与追求 {dede:channelartlist row=1} {dede:arclistsg r ...