怎樣優雅地增刪查改(七):按使用者查詢

2023-07-18 12:00:49

@

實現

定義按使用者查詢(IUserOrientedFilter)介面

public interface IUserOrientedFilter
{
    public string EntityUserIdIdiom { get; }
    Guid? UserId { get; set; }
}

  • EntityUserIdIdiom:語意上的UserId,用於指定業務實體中用於描述「使用者Id」欄位的名稱,若不指定,則預設為「UserId」
  • UserId:使用者Id,若為Guid.Empty,則使用當前登入使用者的Id

查詢實體列表Dto若實現該介面,將篩選指定 UserId 下的關聯的實體。

若指定 UserId 為 Guid.Empty,則使用當前登入使用者的 UserId。

ICurrentUser是Abp的一個服務,用於獲取當前登入使用者的資訊

建立應用過濾條件方法:ApplyUserOrientedFiltered,在此實現拼接LINQ表示式,程式碼如下:

protected virtual IQueryable<TEntity> ApplyUserOrientedFiltered(IQueryable<TEntity> query, TGetListInput input)
{
    if (input is IUserOrientedFilter)
    {
        var filteredInput = input as IUserOrientedFilter;
        var entityUserIdIdiom = filteredInput.EntityUserIdIdiom;
        if (string.IsNullOrEmpty(entityUserIdIdiom))
        {
            entityUserIdIdiom = "UserId";
        }
        if (HasProperty<TEntity>(entityUserIdIdiom))
        {
            var property = typeof(TEntity).GetProperty(entityUserIdIdiom);
            if (filteredInput != null && filteredInput.UserId.HasValue)
            {
                Guid userId = default;
                if (filteredInput.UserId.Value == Guid.Empty)
                {
                    using (var scope = ServiceProvider.CreateScope())
                    {
                        var currentUser = scope.ServiceProvider.GetRequiredService<ICurrentUser>();
                        if (currentUser != null)
                        {
                            userId = currentUser.GetId();
                        }
                    }
                }
                else
                {
                    userId = filteredInput.UserId.Value;
                }

                var parameter = Expression.Parameter(typeof(TEntity), "p");
                var keyConstantExpression = Expression.Constant(userId, typeof(Guid));

                var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                var expression = Expression.Equal(propertyAccess, keyConstantExpression);

                var equalExpression = expression != null ?
                        Expression.Lambda<Func<TEntity, bool>>(expression, parameter)
                        : p => false;

                query = query.Where(equalExpression);
            }
        }
    }
    return query;
}


請注意,可應用過濾的條件為:

  1. input需實現IUserOrientedFilter介面;
  2. 實體必須關聯使用者。

否則將原封不動返回IQueryable物件。

使用

無需在應用層中更改程式碼,

在GetAllAlarmInput中實現IUserOrientedFilter介面,程式碼如下:

public class GetAllAlarmInput : PagedAndSortedResultRequestDto, IUserOrientedFilter
{
    Guid? UserId { get; set; }
    
    public string EntityUserIdIdiom { get; }      
    // 或顯式實現   
    // public string EntityUserIdIdiom => "UserId";
    
    ...
}

測試

建立一些組織架構,命名「群組」

在不同「群組」下建立一些客戶(Client)

在告警管理頁面中,建立一些告警,並將這些告警分配給不同的客戶

告警建立完成後,進入客戶管理,在右側客戶列表中點選「檢視詳情」

開啟客戶詳情頁面,點選「告警」分頁,可以看到該客戶下的告警列表