EF Core中如何更优雅地实现按角色区分数据查询?
更优雅的角色数据过滤实现方式
针对你当前的角色数据过滤需求,这里提供几种更简洁、可维护的实现方案,适配不同复杂度的场景:
1. 条件链式拼接过滤(适合简单场景)
将过滤逻辑拆分为线性的条件拼接,避免分支直接返回,让代码结构更清晰,同时方便后续统一处理分页、数据转换等逻辑:
public async Task<PagedResponse<TodoItemBriefDto>> Handle(GetTodoItemsWithPaginationQuery request, CancellationToken cancellationToken) { var query = _context.Set<TodoItemExample>().AsQueryable(); // 根据角色动态添加过滤条件 if (request.User.RoleId == "OPERATOR") { query = query.Where(x => x.UserId == request.User.Id); } // 统一处理分页与数据转换 var totalCount = await query.CountAsync(cancellationToken); var items = await query .Skip((request.PageNumber - 1) * request.PageSize) .Take(request.PageSize) .ProjectTo<TodoItemBriefDto>(_mapper.ConfigurationProvider) .ToListAsync(cancellationToken); return new PagedResponse<TodoItemBriefDto>(items, totalCount, request.PageNumber, request.PageSize); }
2. 扩展方法封装过滤逻辑(提升代码可读性)
将角色过滤逻辑封装为扩展方法,让业务方法更专注于核心流程,同时过滤逻辑可复用:
首先定义扩展方法:
public static class TodoItemQueryExtensions { public static IQueryable<TodoItemExample> FilterByUserRole(this IQueryable<TodoItemExample> query, User user) { return user.RoleId == "OPERATOR" ? query.Where(x => x.UserId == user.Id) : query; } }
然后在Handle中调用:
public async Task<PagedResponse<TodoItemBriefDto>> Handle(GetTodoItemsWithPaginationQuery request, CancellationToken cancellationToken) { var query = _context.Set<TodoItemExample>() .FilterByUserRole(request.User); // 后续分页与转换逻辑同上 }
3. 策略模式(适合复杂/可扩展场景)
如果未来可能新增角色、扩展过滤逻辑,策略模式能避免大量if-else分支,符合开闭原则:
步骤1:定义策略接口
public interface ITodoItemQueryStrategy { IQueryable<TodoItemExample> ApplyFilter(IQueryable<TodoItemExample> query, User user); }
步骤2:实现各角色策略
// Admin角色策略:无过滤 public class AdminTodoQueryStrategy : ITodoItemQueryStrategy { public IQueryable<TodoItemExample> ApplyFilter(IQueryable<TodoItemExample> query, User user) { return query; } } // Operator角色策略:过滤自己的数据 public class OperatorTodoQueryStrategy : ITodoItemQueryStrategy { public IQueryable<TodoItemExample> ApplyFilter(IQueryable<TodoItemExample> query, User user) { return query.Where(x => x.UserId == user.Id); } }
步骤3:在Handler中使用策略
通过依赖注入注入策略字典,根据角色获取对应策略:
private readonly Dictionary<string, ITodoItemQueryStrategy> _strategyMap; public GetTodoItemsWithPaginationQueryHandler(Dictionary<string, ITodoItemQueryStrategy> strategyMap) { _strategyMap = strategyMap; } public async Task<PagedResponse<TodoItemBriefDto>> Handle(GetTodoItemsWithPaginationQuery request, CancellationToken cancellationToken) { // 匹配策略,默认用Admin策略 var strategy = _strategyMap.TryGetValue(request.User.RoleId, out var matchedStrategy) ? matchedStrategy : _strategyMap["ADMIN"]; var query = strategy.ApplyFilter(_context.Set<TodoItemExample>(), request.User); // 后续分页与转换逻辑同上 }
内容的提问来源于stack exchange,提问作者Lube
相关产品推荐
相关产品推荐

