如何创建动态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
相关产品推荐
相关产品推荐

