利用Abp過濾器實現業務資料「回收站」功能

2023-07-20 12:13:49

@

原理

回收站是當用戶刪除一條記錄時,不是直接從資料庫中刪除,而是將其放入「回收站」,以便使用者可以在需要時恢復資料。

在Abp框架中,若實體實現了ISoftDelete,則將實體標記為刪除時不是物理刪除,而是「軟刪除」

public interface ISoftDelete
{
    /// <summary>
    /// Used to mark an Entity as 'Deleted'. 
    /// </summary>
    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<TEntity>();
    if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
    {
        Expression<Func<TEntity, bool>> 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();