You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linq如何基于用户角色为IQueryable动态添加多个筛选条件

解决方案

问题根因

你的原有代码存在两个问题:

  1. 每次赋值query时都是基于原始的productionUnits数据源做筛选,直接覆盖了上一次的筛选结果
  2. 即使改为query = query.Where(xxx)的写法,多个Where拼接的是AND逻辑,要求同时满足所有条件,自然无法匹配多个生产单元的需求

方案1:收集权限ID用Contains查询(最简单推荐)

如果各角色的筛选规则都是匹配生产单元ID,直接收集所有允许访问的ID,用Contains生成SQL的IN语句即可,全程在IQueryable层面执行,不会提前加载数据:

public void OnGet()
{
    var productionUnits = _context.ProductionUnits;
    // 收集所有有权限的生产单元ID
    var allowedUnitIds = new List<int>();
    if (User.IsInRole(CustomRole.AdministratorUAP1))
    {
        allowedUnitIds.Add((int)ProductionUnitEnum.UAP1);
    }
    if (User.IsInRole(CustomRole.AdministratorUAP2))
    {
        allowedUnitIds.Add((int)ProductionUnitEnum.UAP2);
    }
    // 其他角色规则同理添加

    // 生成查询,EF会自动将Contains翻译为SQL IN语句
    var query = productionUnits.Where(c => allowedUnitIds.Contains(c.Id));
    
    // 后续正常使用query即可
}

如果用户无任何权限,allowedUnitIds为空,查询会直接返回空结果,符合预期。

方案2:动态拼接表达式树(适配复杂筛选规则)

如果不同角色的筛选规则不是简单的ID匹配(比如还要加状态、所属区域等其他条件),可以用OR逻辑拼接表达式树实现,这里可以用LINQKit提供的PredicateBuilder简化代码:

// 需先安装NuGet包LINQKit
public void OnGet()
{
    var productionUnits = _context.ProductionUnits;
    // 初始化条件构造器
    var predicate = PredicateBuilder.New<ProductionUnit>();
    
    if (User.IsInRole(CustomRole.AdministratorUAP1))
    {
        // 可以写任意复杂的筛选条件,用Or拼接
        predicate = predicate.Or(c => c.Id == (int)ProductionUnitEnum.UAP1 && c.IsActive);
    }
    if (User.IsInRole(CustomRole.AdministratorUAP2))
    {
        predicate = predicate.Or(c => c.Id == (int)ProductionUnitEnum.UAP2);
    }
    // 其他角色规则同理添加
    
    // 应用条件生成查询,EF Core可直接使用,旧版EF需要加.AsExpandable()
    var query = productionUnits.Where(predicate);
}

内容的提问来源于stack exchange,提问作者Henrique Pombo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 17:00:00