ABP官方文档翻译 3.8 数据过滤器

数据顾虑器

  • 介绍
  • 预定义过滤器
    • ISoftDelete
    • 何时使用?
    • IMustHaveTenant
    • 何时使用?
    • IMayHaveTenant
    • 何时使用
  • 禁用过滤器
    • 关于using语句
    • 关于多租户
    • 全局禁用过滤器
  • 启用过滤器
  • 设置过滤器参数
    • SetTenantId方法
  • ORM集成
    • Entity Framework
    • EntityFramework.DynaamicFilters文档
    • 其他ORMs

介绍

  软删除模式是常用的模式,这种模式并没有从数据库中删除实体而是打上‘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", 42);

  另一个示例:设置IMayHaveTenant过滤器的tenantId值:

urrentUnitOfWork.SetFilterParameter(AbpDataFilters.MayHaveTenant, AbpDataFilters.Parameters.TenantId, 42);

  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, 0);
}

  “PersonFilter”是过滤器唯一的名称。第二个参数定义了过滤器接口和personId过滤器参数(如果过滤器没有参数可以不需要),最后的参数是personId的默认值。

  最后一件事情,我们必须在模块的PreInitialize方法中注册这个过滤器到ABP的工作单元系统中。

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

  第一个参数是和我们之前定义的同样的名字。第二个参数标示这个过滤器默认是启用还是禁用。声明这么一个参数化过滤器之后,我们可以在运行时提供给他参数值并使用它。

using (CurrentUnitOfWork.EnableFilter("PersonFilter"))
{
    using(CurrentUnitOfWork.SetFilterParameter("PersonFilter", "personId", 42))
    {
        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);

返回主目录
时间: 2024-10-24 05:30:39

ABP官方文档翻译 3.8 数据过滤器的相关文章

Python3.2官方文档翻译--使用二进制数据记录布局和多线程

题目描述 有n张卡片,分别标有数字1~n.有一天Silence把他们按某种序列排好,然后从第一张开始取出一张,再拿一张放到最后面,再取出一张,再拿出一张放到最后面...知道n张卡片全部取走.把取出的卡片按取出的顺序排好,正好是1,2,3,4,....,n. 现在,告诉你n,Silence希望你帮他计算原来的序列的逆序数. 例如,n=4时,原来的序列应该是1,3,2,4.这样,先取出卡片1,再把卡片3放到最后面,序列变成了2,4,3.再把2取出来,4放到后面,序列变成了3,4.再把3取出来,4放最

ABP官方文档翻译 9.3 NHibernate集成

NHibernate集成 Nuget包 配置 实体映射 仓储 默认实现 自定义仓储 应用程序特定基础仓储类 ABP可以使用任何ORM框架,它内置集成NHibernate.此文档将讲解ABP如何使用NHibernate,假定你对NHibernate已经有了一定的了解. Nuget包 在ABP中实现NHibernate做为ORM框架的Nuget包为Abp.NHibernate.你需要在应用程序中添加它.最好在一个单独的程序集中实现NHibernate并在这个程序集里依赖Abp.NHibernate包

ABP官方文档翻译 9.1 EntityFramework集成

EntityFramework集成 Nuget包 DbContext 仓储 默认仓储 自定义仓储 应用特定的基础仓储类 自定义仓储示例 仓储最佳实践 事务管理 数据存储 ABP可以使用ORM框架,它内置集成EntityFramework.本文档将讲解ABP如何使用EntityFramework.假定你对EntityFramework已经有了初级水平. Nuget包 在ABP中使用Abp.EntityFramework nuget包扩展了EntityFramework.需要将它添加到工程中.最好在

ABP官方文档翻译 3.5 规约

规约 介绍 示例 创建规范类 使用仓储规约 组合规约 讨论 什么时候使用? 什么时候不使用? 介绍 规约模式是一种特别的软件设计模式,通过使用布尔逻辑将业务规则链接起来重新调配业务规则.(维基百科). 尤其是,它通常用来为实体或其他业务对象定义可复用的过滤器. 示例 在这个部分,我们将看到规约模式的必要性.本部分是通用的,和ABP的实现没有必然的关系. 假定,有一个服务方法,计算所有客户的总数量,如下所示: public class CustomerManager { public int Ge

ABP官方文档翻译 3.3 仓储

 仓储 默认仓储 自定义仓储 自定义仓储接口 自定义仓储实现 基础仓储方法管理数据库连接 查询 获取单个实体 获取实体列表 关于IQueryable 自定义返回值 插入 更新 删除 其他 关于异步方法 管理数据库连接 仓储生命周期 仓储最佳实践 协调领域和数据映射层,使用类集合接口访问领域对象."(Martin Fowler) 实际上,仓储用来执行领域对象的数据库操作(实体和值类型).通常,每个对象(或聚合根)使用单独的仓储. 默认仓储 在ABP中,仓储类实现IRepository<TEn

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.OData Abp.Web.Resources Abp.Web.SignalR Abp.Owin Abp.EntityFramework.Common Abp.EntityFramework Abp.EntityFramework.GraphDiff Abp.EntityFrameworkCore Ab

ABP官方文档翻译 6.2.1 ASP.NET Core集成

ASP.NET Core 介绍 迁移到ASP.NET Core? 启动模板 配置 启动类 模块配置 控制器 应用服务作为控制器 过滤器 授权过滤器 审计Action过滤器 校验过滤器 工作单元Action过滤器 异常过滤器 结果过滤器 Ajax请求的结果缓存 模型绑定器 视图 客户端代理 集成测试 介绍 本文档描述了ABP如何集成ASP.NET Core.ASP.NET Core通过Abp.AspNetCore nuget包实现集成. 迁移到ASP.NET Core? 如果你已经有一个工程并考虑

ABP官方文档翻译 4.1 应用服务

应用服务 IApplicationService接口 ApplicationService类 CrudService和AsyncCrudAppService类 简单的CRUD应用服务示例 自定义CRUD应用服务 GettingList Create和Update 其他方法参数 CRUD权限 工作单元 应用服务生命周期 应用服务将领域逻辑暴露给展示层.在展示层使用DTO(数据传输对象)作为参数调用应用服务,应用服务使用领域对象执行一些特定的业务逻辑,并返回DTO到展示层.因此,展示层与领域层是完全

ABP官方文档翻译 3.6 工作单元

工作单元 介绍 ABP中的连接和事务管理 传统的工作单元方法 控制工作单元 UnitOfWork特性 IUnitOfWorkManager 工作单元详情 禁用工作单元 无事务工作单元 一个工作单元方法调用另一个 工作单元范围 自动保存更改 IRepository.GetAll()方法 工作单元特性限制 选项 方法 SaveChanges 事件 介绍 在使用数据库的应用中,连接和事务管理是最重要的概念之一.什么时候打开连接,什么时候开始一个事务,如何释放连接等等.ABP使用工作单元系统来管理连接和