ABP(现代ASP.NET样板开发框架)系列之1三、ABP领域层——数据过滤器(Data filters)

点这里进入ABP系列文章总目录html

 

基于DDD的现代ASP.NET开发框架--ABP系列之1三、ABP领域层——数据过滤器(Data filters)
git

 

ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。github

ABP的官方网站http://www.aspnetboilerplate.com数据库

ABP在Github上的开源项目https://github.com/aspnetboilerplate安全

 


 

介绍

在数据库开发中,咱们通常会运用软删除(soft-delete)模式,即不直接从数据库删除数据,而是标记这笔数据为已删除。所以,若是实体被软删除了,那么它就应该不会在应用程序中被检索到。要达到这种效果,咱们须要在每次检索实体的查询语句上添加SQL的Where条件IsDeleted = false。这是个乏味的工做,但它是个容易被忘掉的事情。所以,咱们应该要有个自动的机制来处理这些问题。架构

ABP提供数据过滤器(Data filters),它使用自动化的,基于规则的过滤查询。ABP已经有一些预约义的过滤器,固然也能够自行建立你专属的过滤器。框架

注意:只针对EntityFramework:ABP数据过滤器仅实如今EntityFramework。还没法在其它ORM工具中使用。见其它ORM章节于本文末端。 ide

预约义过滤器

软删除接口(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进行自动的处理。

多租接口(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过滤器。所以,全部的租户的数据均可以被应用程序所检索。注意,这与安全性无关,你应该要对敏感数据进行验证受权处理。

多租接口(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标准的软删除过滤器。

people2亦可取得已标记为删除的People实体,而people1和people3将会是惟一的非已标记为删除的People实体。若配合使用using语法,你能够禁用其控制范围内(Scope)的过滤器。若是你不使用 using 语法 ,此过滤器会被一直禁用,直到工做单元(unit of work)结束或者再度启用它。(意思是:若是你使用"using"关键字声明,过滤器是启用状态;当前工做单元(unit of work)结束后,过滤器是禁止状态。若是不使用"using"关键字声明,默认过滤器是禁用状态,此时能够手动启用过滤器。)

你能够注入IUnitOfWorkManager而且在上述示例中使用。一样的,你可使用CurrentUnitOfWork属性做为一个在应用服务中的简便方式(它是从ApplicationService类继承而来的)。

注意:关于using语法:假如过滤器在你调用DisableFilter方法并配合using语法以前已经是启用,则过滤器会被禁用,而且会自动地在using语法结束后在度启用。可是若过滤器在using语法以前就已经被禁用了,DisableFilter方法实际上并不作任何式,而且过滤器会维持禁用状态即使是using语法的结束后。 

启用过滤器

你能够在工做单元(unit of work)中使用EnableFilter方法启用过滤器,如同DisableFilter方法通常(二者互为正反两面)。EnableFilter亦会返回disposable来自动地从新禁用过滤器。

设定过滤器参数

 过滤器能够被参数化(parametric)。IMustHaveTenant过滤器是这类过滤器的一个范本,由于当前租户(tenant)的Id是在执行时期决定的。对于这些过滤器,若是真有须要,咱们能够改变过滤器的值。举例以下:

CurrentUnitOfWork.SetFilterParameter("PersonFilter", "personId", 42);

另外一个示例以下:设定IMayHaveTenant过滤器的tenantId值:

CurrentUnitOfWork.SetfilterParameter(AbpDataFilters.MayHaveTenant, AbpDataFilters.Parameters.TenantId, 42);

自定义过滤器

欲建立定制的过滤器而且整合到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; }
   }

由于ABP使用EntityFramework.DynamicFilters这个过滤器,咱们使用它的规则(rule)来定义过滤器。在咱们的DbContext类中,咱们重写了OnModelCreating而且定义了过滤器以下示例所示:

  protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      base.OnModelCreating(modelBuilder);
      modelBuilder.Filter("PersonFilter", (IHasPerson entity, int personId) => entity.PersonId == personId, 0 );
   }

PersonFilter过滤器在这里是一个惟一的过滤器名称。再来就是过滤器接口的参数定义和personId过滤器参数(不必定须要,假如过滤器是属于不可参数化(parametric)型),最后一个参数为personId的默认值。

最后一个步骤,咱们须要注册这个过滤器到ABP工做单元(unit of work)系统中,设定的位置在咱们模块里的PreInitialize方法。

Configuration.UnitOfWork.RegisterFilter("PersonFilter", false);

第一个参数是咱们刚刚所定义的惟一名称,第二个参数指示这个过滤器预设是启用仍是禁用。在声明完这些可参数化(parametric)的过滤器后,咱们能够在执行期间指定它的值来操做这个过滤器。

   using(CurrentUnitOfWork.EnableFilter("PersonFilter")) {
      CurrentUnitOfWork.SetFilterParameter("PersonFilter", "personId", 42);
      var phone = _phoneRepository.GetAllList();
      // ...
   }

咱们能够从有些数据源中取得personId而不须要写死在程序代码中。上述示例是为了要可以程序化过滤器。过滤器可拥有0到更多的参数。假如是无参数的过滤器,它就不须要设定过滤器的值。一样地,假如它预设是启用,就不须要手动启用(固然的,咱们也能够禁用它)。

EntityFramework.DynamicFilters的文件:若须要更多关于动态数据过滤器的相关信息,能够见其在git上的文件https://github.com/jcachat/EntityFramework.DynamicFilters

咱们能够为安全性建立一个定制化的过滤器,主/被动实体,多租户...诸如此类的。

其它对象关系映射工具

ABP数据过滤器仅实如今Entity Framework上。对于其它ORM工具则尚不可用。可是, 实际上,你能够模仿这个模式到其它使用仓储来取得数据的案例下。这此案例中, 你能够建立一个定制的仓储而且覆写GetAll方法,若是有须要的话,能够一块儿修改其它资料检索方法。

 


 

但愿更多国内的架构师能关注到ABP这个项目,也许这其中有能帮助到您的地方,也许有您的参与,这个项目能够发展得更好。

欢迎加ABP架构设计交流QQ群:134710707

ABP架构设计交流群

 

点这里进入ABP系列文章总目录

相关文章
相关标签/搜索