根据某些条件与另一个表连接后,在 IQueryable<T> 中设置属性值

Saf*_*afa 5 linq entity-framework iqueryable automapper entity-framework-6

我正在为 WPF 实施授权。我对屏幕有绑定权限。例如,有一个叫地板的屏幕。它有四个与之关联的权限。

  1. 查看楼层
  2. 添加楼层
  3. 编辑楼层
  4. 删除楼层

除了每个权限,我们还有四个级别的权限。

  1. 全部
  2. 自己
  3. 角色
  4. 用户

因此,如果用户具有权限级别为 {ALL} 的 {View Floor} 权限。他们可以查看任何用户创建的所有楼层。

如果用户具有 {Self} 权限级别。他们只能查看自己创建的楼层。

如果用户的权限级别为 {Role}。他们可以查看针对指定角色分配的所有楼层。

权限级别的角色分配如下:

Roles: Supervisor, Technician
Run Code Online (Sandbox Code Playgroud)

如果 BranchManager 具有上述权限级别。然后他可以查看自己创建的楼层以及任何具有主管或技术人员角色的用户创建的楼层。

权限级别 {User} 与 {Role} 相同。

这是我用于获取楼层的 IQueryable:

IQueryable<FloorModel> FloorsQueryable = (from f in Floors
                                          join b in Branches on f.BranchId equals b.Id
                                          where (string.IsNullOrEmpty(filters.Name) || f.Name.ToLower().Contains(filters.Name.ToLower()))
                                          && (string.IsNullOrEmpty(filters.BranchName) || b.Name.ToLower().Contains(filters.BranchName.ToLower()))
                                          && (f.IsDeleted == null || f.IsDeleted == false)
                                          && f.BranchId == CurrentBranchId
                                          && f.ApplicationId == CurrentApplicationId
                                          select new FloorModel
                                          {
                                              Id = f.Id,
                                              Name = f.Name,
                                              Code = f.Code,
                                              Branch = new BranchBriefModel()
                                              {
                                                  Id = f.BranchId,
                                                  Name = b.Name,
                                              },
                                              IsActive = f.IsActive ?? false,
                                              Description = f.Description,
                                              CreatedBy = f.CreatedBy ?? 0,
                                              ApplicationId = CurrentApplicationId,
                                          }).AsQueryable();
Run Code Online (Sandbox Code Playgroud)

在此之后,我需要根据权限级别对这个查询应用一些自定义过滤器

FloorsQueryable = CustomFilter(FloorsQueryable,CurrentUserId,filters);
Run Code Online (Sandbox Code Playgroud)

自定义过滤器代码

public IQueryable<T> CustomFilter<T>(IQueryable<T> query, int CurrentUserId, BaseSearchModel search) where T : BaseModel, new()
{
    var distinctClaims = search.ScreenPermission.Select(x => x.Claim.PermissionLevel).Distinct().ToList();
    var viewPermission = search.ScreenPermission.Where(x => x.Name.Contains("View")).FirstOrDefault();
    if (viewPermission != null && viewPermission.Claim.PermissionLevel != PermissionLevelCatalog.All)
    {
        if (distinctClaims.Any(x => x == PermissionLevelCatalog.Role))
        {
            query = (from q in query
                     join ur in UsersInRoles on q.CreatedBy equals ur.UserId
                     join r in Roles on ur.RoleId equals r.Id
                     select q);
        }
        string propertyName = "CreatedBy";
        //if (string.IsNullOrEmpty(propertyName))
        //    return query;
        // we have parameter "generic"
        var selectorParameter = Expression.Parameter(typeof(T), "generic");
        // constant "CurrentUserId"
        var searchTermExpression = Expression.Constant(CurrentUserId);
        // "generic.CreatedBy"
        var selector = Expression.PropertyOrField(selectorParameter, propertyName);
        // "generic.CreatedBy == "CurrentUserId"
        var equal = Expression.Equal(selector, searchTermExpression);
        // generic => generic.Name == "CurrentUserId"
        var genericWhere = Expression.Lambda<Func<T, bool>>(equal, selectorParameter);
        query = query.Where(genericWhere);
    }
    return query;
}
Run Code Online (Sandbox Code Playgroud)

现在对于权限级别 {Role},我需要在 IQueryable 的 select 子句中添加 CreatorRoleId 以在以下代码中应用所需的检查。

if (distinctClaims.Any(x => x == PermissionLevelCatalog.Role))
{
    query = (from q in query
            join ur in UsersInRoles on q.CreatedBy equals ur.UserId
            join r in Roles on ur.RoleId equals r.Id
            select q
            );
}
Run Code Online (Sandbox Code Playgroud)

是否可以设置 CreatorRoleId 的值?像下面这样的东西

select {q=>q.CreatorRoleId=r.Id return q;}
Run Code Online (Sandbox Code Playgroud)

这应该是通用的,可以为任何 IQueryable 运行。我不想为项目中的所有查询加入 Role 和 UserInRole 表,因为只有当某些用户具有此 {Role} 权限级别时才需要这些联接。