数据过滤器(Data filters)
在数据库开发中,我们一般会运用软删除(soft-delete)模式,即不直接从数据库删除数据,而是标记这笔数据为已删除。因此,如果实体被软删除了,那么它就应该不会在应用程序中被检索到。要达到这种效果,我们需要在每次检索实体的查询语句上添加SQL的Where条件IsDeleted = false。这是个乏味的工作,但它是个容易被忘掉的事情。因此,我们应该要有个自动的机制来处理这些问题。
ABP提供数据过滤器(Data filters),它使用自动化的,基于规则的过滤查询。ABP已经有一些预定义的过滤器,当然也可以自行创建你专属的过滤器。
注意:只针对EntityFramework:ABP数据过滤器仅实现在EntityFramework。还无法在其它ORM工具中使用。见其它ORM章节于本文末端。
预定义过滤器
1.软删除接口(ISoftDelete)
软删除过滤器(Soft-delete filter )会过滤从数据库查询出来的实体且是自动套用(从结果集中提取出来)。如果实体需要被软删除,它需要实现ISoftDelete接口,该接口仅定义了一个IsDeleted属性。例:
public class Person : Entity, ISoftDelete { public virtual string Name { get; set; } public virtual bool IsDeleted { get; set; } }
Person实体实际上并没有从数据库中被删除,当删除此实体时,IsDeleted属性值会被设定为true。当你使用IRepository.Delete方法时,ABP会自动完成这些工作(你可以手动设定IsDeleted为true,但是Delete方法更加自然且是较建议的方式)。
当实现了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方法仅取得Person实体,该实体其IsDeleted = false(非删除状态)。所有的仓储方法以及导航属性都能够正常运作。我们可以添加一些其它的Where条件,Join...等等。它将会自动地添加IsDeleted=false条件到生成的SQL查询语句中。
注意:何时启用?ISoftDelete过滤器总是启用,除非你直接禁用它。
提醒:如果你实现了IDeletionAudited接口(该接口继承自ISoftDelete),删除创建时间和被删除的用户Id,这些都会由ABP进行自动的处理。
2.多租接口(IMustHaveTenant)
如果你创建一个多租户的应用程序(储存所有租户的数据于单一一个数据库中),你肯定不会希望某个租户看到其它租户的资料。你可以实现IMustHaveTenant接口于此案例中,示例如下:
public class Product : IMustHaveTenant { public virtual int TenantId { get; set; } public virtual string Name { get; set; } }
IMustHaveTenant定义了TenantId来区别不同的租户实体。ABP使用IAbpSession来取得当前TenantId并且自动地替当前租户进行过滤查询的处理。
注意:何时启用?IMustHaveTenant默认是启用的。如果当前使用并没有登入到系统或是当前用户是一个管理级使用者(管理级使用者即为一个最高权限的使用者,它可以管理所有租户和租户的资料),ABP会自动地禁用IMustHaveTenant过滤器。因此,所有的租户的数据都可以被应用程序所检索。注意,这与安全性无关,你应该要对敏感数据进行验证授权处理。
3.多租接口(IMayHaveTenant)
如果一个实体类由多个租户(tenant)以及管理级使用者(host)所共享(这意味着该实体对象或许由租户(tenant)或是管理级使用者(host)所掌控),你可以使用IMayHaveTenantfilter。IMayHaveTenant接口定义了TenantId但是它是可空类(nullable)。
public class Product : IMayHaveTenant { public virtual int? TenantId { get; set; } public virtual string Name { get; set; } }
当为null值,则代表这是一个管理级使用者(host)所掌控的实体,若为非null值,则代表这个实体是由租户(tenant)所掌控,而其Id值即为TenantId。ABP使用IAbpSession接口来取得当前TenantId。IMayHaveTenant过滤器并不如IMustHaveTenant普遍常用。但是当作为管理级使用者(host)和租户(tenant)所需要的通用结构使用时,你或许会需要用到它。
何时启用?IMayHaveTenant接口总是启用的,除非你直接禁用它。
禁用过滤器
可以在工作单元(unit of work)中调用DisableFilter方法来禁用某个过滤器,如下所示:
var people1 = _personRepository.GetAllList(); using(_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete)) { var people2 = _personRepository.GetAllList(); } var people3 = _personRepository.GetAllList();
DisableFilter方法取得一或多个过滤器名称,且类型皆为string。AbpDataFilters.SoftDelete是一个常数字符串其包含了ABP标准的软删除过滤器。