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

如何创建动态LINQ Expression?EF全局查询过滤器实现求助

用动态LINQ Expression实现EF全局查询过滤器

问题缘由

在Entity Framework的OnModelCreating方法里执行原有代码时,currentUser会返回null,而且原有代码里的内存集合查询没法被EF解析成SQL,所以得把全局查询过滤器改成动态LINQ Expression的形式。

原有问题代码

User currentUser = currentUserService.GetUser();
IPermissionService permissionService = DependencyResolver.Current.GetService<IPermissionService>();

var allowedToSee = Entities.Where(e => permissionService.HasPermission(e, currentUser).View);
modelBuilder.Entity<Audit>().HasQueryFilter(x => allowedToSee.Contains(x.EntityType));

Audit类定义

public class Audit
{
    // 变更相关信息

    public virtual Entity EntityType { get; set; }
}

动态表达式实现方案

要做EF能解析的全局查询过滤器,得手动拼表达式树,替换原来直接调用服务和用内存集合的逻辑,具体代码如下:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 定位Audit实体类型
    var auditEntityType = modelBuilder.Model.GetEntityTypes().First(t => t.ClrType == typeof(Audit));
    // 创建表达式参数,对应过滤器里的x
    var parameter = Expression.Parameter(auditEntityType.ClrType, "x");
    
    // 获取Audit类里的EntityType属性表达式
    var entityTypeProperty = Expression.Property(parameter, nameof(Audit.EntityType));
    
    // 构建权限判断的核心表达式(这里要根据你的实际权限逻辑调整)
    // 注意:不能直接在表达式里调用permissionService,得转成EF能解析的实体属性判断
    // 示例:假设我们要判断EntityType的Id是否在允许的列表里
    // 注意:允许的ID列表不能在OnModelCreating阶段硬编码,得在查询执行时动态获取,这里先占位
    var allowedEntityIds = new List<int>(); // 实际要从权限服务动态获取,建议通过DbContext注入服务来实现
    var allowedIdsConstant = Expression.Constant(allowedEntityIds);
    
    // 获取Entity类的Id属性表达式
    var entityTypeIdProperty = Expression.Property(entityTypeProperty, nameof(Entity.Id));
    // 找到Enumerable.Contains方法的泛型版本
    var containsMethod = typeof(Enumerable).GetMethods()
        .First(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2)
        .MakeGenericMethod(typeof(int));
    // 构建Contains调用表达式:allowedEntityIds.Contains(x.EntityType.Id)
    var containsExpression = Expression.Call(containsMethod, allowedIdsConstant, entityTypeIdProperty);
    
    // 把表达式包装成Lambda,作为查询过滤器
    var filterLambda = Expression.Lambda(containsExpression, parameter);
    
    // 给Audit实体设置全局查询过滤器
    modelBuilder.Entity<Audit>().HasQueryFilter(filterLambda);

    base.OnModelCreating(modelBuilder);
}

重点提醒

  • OnModelCreating只在DbContext初始化时执行一次,这时候拿不到当前用户,所以权限逻辑必须是查询执行时能动态生效的——比如给DbContext注入权限服务,或者把权限判断转成实体属性的条件,让EF能翻译成SQL。
  • 别直接在表达式里调用服务方法,EF没法把这种调用转成SQL,必须拆成基于实体属性的表达式逻辑。
  • 如果权限逻辑复杂,可以单独写个工具类来封装表达式构建逻辑,方便复用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 16:21:01