• 利用Abp过滤器实现业务数据“回收站”功能


    @

    原理

    回收站是当用户删除一条记录时,不是直接从数据库中删除,而是将其放入“回收站”,以便用户可以在需要时恢复数据。

    在Abp框架中,若实体实现了ISoftDelete,则将实体标记为删除时不是物理删除,而是“软删除”

    public interface ISoftDelete
    {
        /// 
        /// Used to mark an Entity as 'Deleted'. 
        /// 
        bool IsDeleted { get; set; }
    }
    

    当使用仓储删除一条记录时,ABP会自动将 IsDeleted 设置为true,并将删除操作替换为修改操作。 在查询数据库时会自动过滤软删除的实体。

    利用这个原理,可以将“软删除”行为认为是放入了“回收站”,而将“恢复”行为认为是从“回收站”中取出。将记录硬删除的行为认为是“永久删除”, 将全部已“软删除”的记录硬删除,则是“清空回收站”

    因此我需要实现一个自定义过滤器,用于查看已删除的实体。

    创建过滤器

    定义仅查看软删除的过滤器,命名"OnlyShowSoftDelete"

    public class FileDataFilters
    {
        public const string OnlyShowSoftDelete = "OnlyShowSoftDelete";
    
    }
    

    在模块中注册过滤器,isEnabledByDefault参数为false,默认不启用

    Configuration.UnitOfWork.RegisterFilter(FileDataFilters.OnlyShowSoftDelete, false);
    

    在DbContext中,增加IsOnlyShowSoftDeleteFilterEnabled属性,用于判断当前的查询上下文中是否启用了“仅查看软删除”过滤器

    public bool IsOnlyShowSoftDeleteFilterEnabled => CurrentUnitOfWorkProvider?.Current?.IsFilterEnabled(FileStorage.Uow.FileDataFilters.OnlyShowSoftDelete) == true;
    
    

    在DbContext中,重写CreateFilterExpression方法,当启用了“仅查看软删除”过滤器时,自动过滤软删除的实体

    protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
    {
        var expression = base.CreateFilterExpression();
        if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
        {
            Expressionbool>> softDeleteFilter = e => !IsOnlyShowSoftDeleteFilterEnabled || ((ISoftDelete)e).IsDeleted;
            expression = expression == null ? softDeleteFilter : CombineExpressions(expression, softDeleteFilter);
        }
    
        return expression;
    }
    
    

    使用过滤器

    查询

    查询正常业务时,不需要对默认的过滤器做操作。

    在查看“回收站”中的数据时,需要关闭AbpDataFilters.SoftDelete过滤器,打开FileDataFilters.OnlyShowSoftDelete过滤器。

    在使用仓储做任何查询(如: GetAll或Get)之前,加入以下代码:

    UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete);
    UnitOfWorkManager.Current.EnableFilter(FileDataFilters.OnlyShowSoftDelete);
    

    删除

    在删除记录时,通过调用仓储的Delete()方法,将记录放入“回收站”中。调用HardDelete()方法,将记录永久删除。

    
    public virtual async Task DeleteAsync(File file, bool isHardDelete = false)
    {
        if (isHardDelete)
        {
            await _repository.HardDeleteAsync(file);  //永久删除
        }
        else
        {
            await _repository.DeleteAsync(file);       //放入“回收站”
        }
    }
    
    

    恢复

    获取已经“软删除”的记录,调用UnDelete()方法,将记录从“回收站”中取出

    UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.SoftDelete);
    UnitOfWorkManager.Current.EnableFilter(FileDataFilters.OnlyShowSoftDelete);
    
    var currentFile = await _repository.GetAsync(file.Id);
    currentFile.UnDelete();
    
    

    新版Volo.Abp的控制器配置

    新版本的Volo.Abp,取消了字符串配置方式,需要为控制器指定一个接口。

    创建IOnlyShowSoftDelete接口:

    public interface IOnlyShowSoftDelete
    {
    }
    

    添加配置,将默认的控制器状态设置为不启用

    Configure(options =>
    {
        options.DefaultStates[typeof(IOnlyShowSoftDelete)] = new DataFilterState(isEnabled: false);
    });
    

    同样,在DbContext中,重写CreateFilterExpression方法,当启用了“仅查看软删除”过滤器时,自动过滤软删除的实体

    protected bool IsOnlyShowSoftDeleteFilterEnabled => DataFilter?.IsEnabled() ?? false;
    
    protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
    {
        var expression = base.CreateFilterExpression();
    
        if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
        {
            Expressionbool>> softDeleteFilter = e => !IsOnlyShowSoftDeleteFilterEnabled || ((ISoftDelete)e).IsDeleted;
            expression = expression == null ? softDeleteFilter : CombineExpressions(expression, softDeleteFilter);
        }
    
        return expression;
    }
    
    
    

    注入 IDataFilter 服务到你的类中

    private readonly IDataFilter _dataFilter;
    
    public MyBookService(IDataFilter dataFilter)
    {
        _dataFilter = dataFilter;
    }
    
    

    使用_dataFilter的Enable和Disable方法,启用或禁用过滤器

    
    public async Task<List<Book>> GetAllBooksAsync()
    {
        if(input.IncludeTrash)
        {
            //临时显示软删除的记录
            using ( _dataFilter.Disable())
            using ( _dataFilter.Enable())
            {
                return await _bookRepository.GetListAsync();
            }
        }
        else
        {
            return await _bookRepository.GetListAsync();
        }
    }
    

    或使用UnitOfWorkManager解析IDataFilter服务

    using (input.IncludeTrash ? this.UnitOfWorkManager.Current.ServiceProvider.GetRequiredService>().Disable() : NullDisposable.Instance)
    using (input.IncludeTrash ? this.UnitOfWorkManager.Current.ServiceProvider.GetRequiredService>().Enable() : NullDisposable.Instance)
    {
        return await _bookRepository.GetListAsync();
    }
    
  • 相关阅读:
    【Vue五分钟】 五分钟了解Vue的基础篇
    实验二 图像的空间域增强
    .NET中的Object类学习3_MemberwiseClone方法
    bootstrap和react
    Oracle 存储过程
    ElasticSearch(一)
    【人工智能】百度文心一言智能体:AI领域的新里程碑
    【实践出真理】import和require的引入方式真的和网上说的一样吗
    《自卑与超越》爱情篇
    博客系统中的加盐算法
  • 原文地址:https://www.cnblogs.com/jevonsflash/p/17567356.html