返回总目录


本篇目录

介绍###

软删除模式通常用于不会真正从数据库删除一个实体而是仅仅将它标记为"已删除的"。这样,如果一个实体是软删除的,那么它不应该在应用中检索到。为了实现这个目的,我们应该在每一个select实体查询操作中添加一个SQL where条件,如“IsDeleted=false”。这是乏味但是很重要的一项容易忘记的任务。因此,这项工作应该自动完成。

ABP提供了数据过滤器,它们可以基于某些规则自动过滤查询。有很多预定义的过滤器,但你也可以创建自己的过滤器。

预定义过滤器###

ISoftDelete

软删除过滤器用于当查询数据库时自动过滤(从结果中提取)已经删除的实体。如果实体应该是软删除的,那么它必须实现只定义了IsDelete属性的 ISoftDelete接口,例如:

public class Person : Entity, ISoftDelete
{
public virtual string Name { get; set; } public virtual bool IsDeleted { get; set; }
}

实际上,Person实体并没有从数据库中删除,只是当要删除它时将它的 IsDelete属性设置成了true。当使用 IRepository.Delete方法时,ABP会自动处理(你可以手动设置IsDelete为true,但是Delete方法更自然且更受人欢迎)。

实现了ISoftDelete之后,当从数据库获取Person的列表时,已经软删除的person是不会检索到的。这里有一个使用了person仓储获得所有person的例子:

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添加到生成的Sql查询中。

何时开启ISoftDelete呢?

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呢?

IMustHaveTenant默认是开启的。

如果当前的用户没有登录到系统或者当前的用户是一个租主用户(租主用户是可以管理租户和租户数据的更高级用户),ABP会自动关闭IMustHaveTenant过滤器。因此,所有租户的所有数据都可以被检索到。注意这是没有涉及到安全的情况,你应该总是要对敏感的数据进行授权。

IMayHaveTenant

如果一个实体类是租户和租主共享的(这意味着一个实体对象可能被一个租户或者租主拥有),那么你可以使用IMayHaveTenant过滤器。IMayHaveTenant接口定义了ITenantId但是它是 nullable

public class Role : Entity, IMayHaveTenant
{
public int? TenantId { get; set; } public string RoleName { get; set; }
}

如果TenantId的值是null,就意味着这是一个 租主实体;如果值不为null,就意味着该实体被一个 租户拥有,该租户的Id就是该TenantId。ABP使用了IAbpSession来获得当前的TenantId。IMayHaveTenant过滤器不像IMustHaveTenant过滤器那样常用,但是,对于租户和租户公用的结构,你可能需要它。

何时开启IMayHaveTenant呢?

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可以获得已经删除的person实体,然而people1和people3只会获得没有删除的实体。使用 using语句,你可以在一个 作用域(scope)中关闭过滤器。如果你没有使用using语句,那么过滤器在当前工作单元结束前都是关闭的,除非你显式再次开启它。

你可以像上面的例子那样注入IUnitOfWorkManager使用。此外,你也可以在应用服务(它派生自ApplicationService类)中使用CurrentUnitOfWork属性作为快捷方式。

关于using语句

如果过滤器是开启的,当你在using语句中调用DisableFilter方法时,那么过滤器会关闭,然后,当using语句结束时,它会自动再次开启。但是如果在使用using语句之前过滤器已经关闭了,那么DisableFilter实际上什么都不会做,而且在using语句结束后仍然是关闭的。

开启过滤器###

你可以在工作单元中使用EnableFilter方法来开启一个过滤器,和DisableFilter很相似。EnableFilter也返回disable来自动再次关闭该过滤器。

设置过滤器参数###

过滤器是可以带参数的。IMustHaveTenant过滤器就是这些过滤器类型的一个例子,因为当前的租户Id要在运行时确定。对于这些过滤器,如果需要的话,我们可以改变过滤器的值。例如:

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

另一个例子:为IMayHaveTenant过滤器设置tenantId值:

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

SetFilterParameter方法也返回一个IDisposable。因此,我们可以在一个using语句中使用它,在using语句结束时自动还原旧值

定义自定义过滤器###

要创建一个自定义过滤器并集成到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,因此我们可以使用它的规则来定义该过滤器。在我们的 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"))
{
CurrentUnitOfWork.SetFilterParameter("PersonFilter", "personId", 42);
var phones = _phoneRepository.GetAllList();
//...
}

我们可以从一些源中获得personId而不是静态代码中。上面的例子是对于参数化的过滤器来说的。过滤器可以有零个或更多的参数。如果它没有参数,就不需要设置过滤器的值了。此外,如果它默认是开启的,它就不需要手动开启了(当然,我们还可以关闭它)。

EntityFramework.DynamicFilters文档

关于动态数据过滤器的更多信息,请看github上的文档

我们也可以为安全,激活/未激活的实体等创建自定义的过滤器。

其他ORM###

ABP已经实现了EF和NH的数据过滤。对于其他的ORM还不可用。但是实际上,只要你使用仓储获得数据,你就可以为绝大多数情况模拟数据过滤。对于这种情况,如果需要的话,你可以创建自定义的仓储,然后重写 GetAll和其他的数据检索方法。

ABP理论学习之数据过滤器的更多相关文章

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

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之13.ABP领域层——数据过滤器(Data filters) ABP是“ASP.NET Boilerplate P ...

  2. ABP中的数据过滤器

      本文首先介绍了ABP内置的软删除过滤器(ISoftDelete)和多租户过滤器(IMultiTenant),然后介绍了如何实现一个自定义过滤器,最后介绍了在软件开发过程中遇到的实际问题,同时给出了 ...

  3. ABP 配置全局数据过滤器

    ABP官方数据过滤的地址:https://aspnetboilerplate.com/Pages/Documents/Data-Filters 中文可以看这个:https://aspnetboiler ...

  4. ABP 配置全局数据过滤器 II

    第一篇 那种写法有些复杂, 简单办法是直接注入 切换到 ***.EntityFramework 项目 在Uow 里面创建 ***EfUnitOfWork.cs 类 public class Coope ...

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

    数据过滤器 介绍 预定义过滤器 ISoftDelete 何时使用? IMustHaveTenant 何时使用? IMayHaveTenant 何时使用 禁用过滤器 关于using语句 关于多租户 全局 ...

  6. ABP的数据过滤器(Data Filters)

    http://www.aspnetboilerplate.com/Pages/Documents/Data-Filters 我们在数据库开发中,一般会运用软删除 (soft delete)模式 ,即不 ...

  7. 文章翻译:ABP如何在EF core中添加数据过滤器

    原文地址:https://aspnetboilerplate.com/Pages/Documents/Articles%5CHow-To%5Cadd-custom-data-filter-ef-cor ...

  8. ABP理论学习之开篇介绍

    返回总目录 为了和2016年春节赛跑,完成该系列博客,我牺牲了今天中午的时间来完成该系列的第一篇----开篇介绍.开篇介绍嘛,读过大学教材的同学都知道,这玩意总是那么无聊,跟考试没关系,干脆直接跳过, ...

  9. ABP理论学习之多租户

    返回总目录 本篇目录 什么是多租户 ABP中的多租户 什么是多租户 维基百科:"软件多租户是指一种软件架构,在这种软件架构中,软件的一个实例运行在服务器上并且为多个租户服务".一个 ...

随机推荐

  1. direct path read

    在11g中,全表扫描可能使用direct path read方式,绕过buffer cache,这样的全表扫描就是物理读了. 在10g中,都是通过gc buffer来读的,所以不存在direct pa ...

  2. Express URL跳转(重定向)的实现

    Express URL跳转(重定向)的实现   Express是一个基于Node.js实现的Web框架,其响应HTTP请求的response对象中有两个用于URL跳转方法res.location()和 ...

  3. 如何用hypermesh生成包含interface的流体网格

    在计算气动声学的时候,有些情况是需要我们提取流体计算的结果作为声学分析的边界条件,但是,有些流体网格因为物理模型的问题需要我们设定interface,恰恰你是机械,对流体了解一点,又不想花费太多时间来 ...

  4. java中注解的使用与实例(一)

    注解目前非常的流行,很多主流框架都支持注解,而且自己编写代码的时候也会尽量的去用注解,一时方便,而是代码更加简洁. 注解的语法比较简单,除了@符号的使用之外,它基本与Java固有语法一致.Java S ...

  5. 2019年台积电进军AR芯片,将用于下一代iPhone

    近日,有报道表示台积电10nm 芯片可怜的收益率可能会对 2017 年多款高端移动设备的推出产生较大的影响,其中自然包括下一代 iPhone 和 iPad 机型.不过,台积电正式驳斥了这一说法,表明1 ...

  6. Linux mips64r2 PCI中断路由机制分析

    Linux mips64r2 PCI中断路由机制分析 本文主要分析mips64r2 PCI设备中断路由原理和irq号分配实现方法,并尝试回答如下问题: PCI设备驱动中断注册(request_irq) ...

  7. Android RecyclerView 的简单使用

    Android L SDK发布的,新API中最有意思的就是RecyclerView (后面为RV) 和 CardView了, 按照官方的说法, RV 是一个ListView 的一个更高级更灵活的一个版 ...

  8. mac 之 jmeter下载、解压、启动

    1:下载地址:http://jmeter.apache.org/download_jmeter.cgi 2:双击下载的zip文件,即可解压 3:打开终端,cd 到解压的目录下 例如:cd  /User ...

  9. MongoDB的安装与设置MongoDB服务

    Mongo DB 是目前在IT行业非常流行的一种非关系型数据库(NoSql),其灵活的数据存储方式备受当前IT从业人员的青睐.Mongo DB很好的实现了面向对象的思想(OO思想),在Mongo DB ...

  10. Torch7 Tensor切片总结

    1.narrow(k,m,n) 这个函数是选中第k维的从m行开始,供选中n行 2.sub(dim1s,dim1e[,dim2s,dim2e,..,dim4s,dim4e]) 功能最强大,可以切任意的一 ...