zoukankan      html  css  js  c++  java
  • ABP的数据过滤器(Data Filters)

    我们在数据库开发中,一般会运用软删除 (soft delete)模式 ,即不直接从数据库删除数据 ,而是标记这笔数据为已删除。因此 ,如果实体被软删除了,那么它就应该不会在应用程序中被检索到。要达到这种效果 ,我们需要在每次检索实体的查询语句上添加 SQL的 Where条件 IsDeleted = false 。这是个乏味的工作 。但它是个容易被忘掉的事情。因此 ,我们应该要有个自动的机制来处理这些问题 。
    ABP 提供数据过滤器 (Data filters),它使用 自动化的,基于规则的过滤查询。
     
    ABP已做好的过滤器
    ISoftDelete
    publicclass Person : Entity, ISoftDelete
    {
        publicvirtualstring Name { get; set; }
    
        publicvirtualbool IsDeleted { get; set; }
    }
    如上面的Person类,实现了ISoftDelete接口,当我们使用IRepository.Delete方法删除一个Person时,该Person并不真的从数据库删除,仅仅是IsDeleted属性被设置为true。
    publicclass MyService
    {
        privatereadonly IRepository<Person> _personRepository;
    
        publicMyService(IRepository<Person> personRepository)
        {
            _personRepository = personRepository;
        }
    
        public List<Person> GetPeople()
        {
            return _personRepository.GetAllList();
        }
    }
    GetPeople method only gets Person entities which has IsDeleted = false (not deleted). All repository methods and also navigation properties properly works. We could add some other Where conditions, joins.. etc. It will automatically add IsDeleted = false condition properly to the generated SQL query.
    如上面代码,如果某个Person已经被软删除,那么使用IRepository获取所有Person数据时,过滤器会自动过滤掉已经软删除的Person,也就是说,GetAll不是获取实际上数据库还存有的所用Person数据,而是排除了之前被软删除的数据了。
    A side note: If you implement IDeletionAudited (which extends ISoftDelete) then deletion time and deleter user id are also automatically set by ASP.NET Boilerplate.
     
    IMustHaveTenant
    publicclass Product : IMustHaveTenant
    {
        publicvirtualint TenantId { get; set; }
            
        publicvirtualstring Name { get; set; }
    }
    如果你创建了一个多租户的应用程序(储存所有租户的数据于单一一个数据库中),你肯定不会希望某个租户看到其他租户的资料,此时你可以实现IMustHaveTenant接口。
    ABP会使用IABPSession来取得当前TenantId并且自动地替当前租户进行过滤查询处理。
    If current user is not logged in to the system or current user is a host user (Host user is an upper level user that can manage tenants and tenant datas), ASP.NET Boilerplate automatically disables IMustHaveTenant filter. Thus, all data of all tenant's can be retrieved to the application. Notice that this is not about security, you should always authorize sensitive data.
     
    IMayHaveTenant
    publicclass Product : IMayHaveTenant
    {
        publicvirtualint? TenantId { get; set; }
            
        publicvirtualstring Name { get; set; }
    }
    If an entity class shared by tenants and the host (that means an entity object may be owned by a tenant or the host), you can use IMayHaveTenant filter.
    IMayHaveTenant接口定义了TenantId,但是注意它是int?类型,可为空。
    null value means this is a host entity, a non-null value means this entity owned by a tenant which's Id is the TenantId. ASP.NET Boilerplate uses IAbpSession to get current TenantId. IMayHaveTenant filter is not common as much as IMustHaveTenant. But you may need it for common structures used by host and tenants.
     
    禁用过滤器
    var people1 = _personRepository.GetAllList();
    
    using (_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete))
    {
        var people2 = _personRepository.GetAllList();                
    }
    
    var people3 = _personRepository.GetAllList();
    启用过滤器
    也就是使用_unitOfWorkManager.Current.EnableFilter方法
     
    设定过滤器参数
    CurrentUnitOfWork.SetFilterParameter("PersonFilter", "personId", 42);
    CurrentUnitOfWork.SetFilterParameter(AbpDataFilters.MayHaveTenant, AbpDataFilters.Parameters.TenantId, 42);
    自定义过滤器
     

    首先定义一个接口:

    publicinterface IHasPerson
    {
        int PersonId { get; set; }
    }

    实现接口:

    publicclass Phone : Entity, IHasPerson
    {
        [ForeignKey("PersonId")]
        publicvirtual Person Person { get; set; }
        publicvirtualint PersonId { get; set; }
    
        publicvirtualstring Number { get; set; }
    }

    重写DbContext类中的OnModelCreating 方法(用的EntityFramework.DynamicFilters,参考https://github.com/jcachat/EntityFramework.DynamicFilters):

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

    "PersonFilter" is the unique name of the filter here. Second parameter defines filter interface and personId filter parameter (not needed if filter is not parametric), last parameter is the default value of the personId.

    最后,我们要把过滤器注册到ABP的工作单元系统中,以下代码需要写在模块的Preinitialize方法里:

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

    First parameter is same unique name we defined before. Second parameter indicates whether this filter is enabled or disabled by default. After declaring such a parametric filter, we can use it by supplying it's value on runtime.

    using (CurrentUnitOfWork.EnableFilter("PersonFilter"))
    {
        CurrentUnitOfWork.SetFilterParameter("PersonFilter", "personId", 42);
        var phones = _phoneRepository.GetAllList();
        //...
    }
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    .net基础学java系列(一)视野
    技术栈
    Apollo(阿波罗)携程开源配置管理中心
    .NET 动态调用WCF
    RPC 工作原理
    ServiceStack 简单使用
    PRC 框架选择
    栈vs堆,最详细的对比
    使用SuperSocket打造逾10万长连接的Socket服务
    开源项目练习EF+jQueryUI前后端分离设计
  • 原文地址:https://www.cnblogs.com/sagacite/p/4592808.html
Copyright © 2011-2022 走看看