Entity Framework仓储Get()方法如何基于指定属性实现动态过滤查询
实现方案
方案1:手动构建表达式树(无额外依赖,适合简单场景)
这种方案适合需求比较固定,仅需要支持少量属性和操作符的场景,不需要引入第三方依赖。
首先实现通用的过滤表达式构建方法:
using System.Linq.Expressions; using System.Reflection; public static Expression<Func<TEntity, bool>> BuildFilter<TEntity>(string propertyName, string operatorStr, object filterValue) { // 构造Lambda参数 e => ... var parameter = Expression.Parameter(typeof(TEntity), "e"); // 构造属性访问表达式 e.PropertyName var propertyAccess = Expression.Property(parameter, propertyName); // 构造值常量,自动匹配属性类型 var constantValue = Expression.Constant(Convert.ChangeType(filterValue, propertyAccess.Type)); // 根据操作符生成对应表达式 Expression filterBody = operatorStr.ToLower() switch { "eq" => Expression.Equal(propertyAccess, constantValue), "ne" => Expression.NotEqual(propertyAccess, constantValue), "contains" => Expression.Call(propertyAccess, typeof(string).GetMethod("Contains", new[] { typeof(string) })!, constantValue), _ => throw new NotSupportedException($"暂不支持操作符:{operatorStr}") }; // 组装为完整Lambda表达式返回 return Expression.Lambda<Func<TEntity, bool>>(filterBody, parameter); }
接下来只需要解析你传入的$filter查询字符串,调用上面的方法生成过滤表达式,再传入你现有的仓储Get方法即可:
// 示例:解析 $filter=Name eq 'XYZ' string rawFilter = "Name eq 'XYZ'"; var filterSegments = rawFilter.Split(' ', StringSplitOptions.RemoveEmptyEntries); string propertyName = filterSegments[0]; string op = filterSegments[1]; string value = filterSegments[2].Trim('\''); // 生成Team实体的过滤表达式 var teamFilter = BuildFilter<Team>(propertyName, op, value); // 调用现有仓储方法查询 var queryResult = _teamRepository.Get(filter: teamFilter);
方案2:使用第三方库(适合复杂过滤场景)
如果需要支持多属性组合过滤、嵌套逻辑、全量OData $filter语法,可以直接用成熟的类库,避免手写大量表达式树逻辑。
- 安装NuGet包
System.Linq.Dynamic.Core
Install-Package System.Linq.Dynamic.Core
- 直接用过滤字符串生成查询条件:
using System.Linq.Dynamic.Core; // 直接解析字符串生成Where条件,支持参数化避免SQL注入 var filterResult = Entities.Where("Name == @0", "XYZ").ToList();
如果需要完全兼容OData的$filter、$orderby等参数规范,直接使用微软官方的Microsoft.AspNetCore.OData包即可自动完成参数解析和查询构造。
注意事项
- 手写表达式树时必须对属性名、操作符做白名单校验,避免用户传入非法参数导致程序报错或数据泄露
- 过滤逻辑是基于
IQueryable生成的,会被EF转换为SQL在数据库端执行,不会将全量数据加载到内存后过滤,性能符合预期 - 禁止直接拼接SQL字符串,所有过滤值都要走参数化逻辑,避免SQL注入风险
内容的提问来源于stack exchange,提问作者Jay Modi
相关产品推荐
相关产品推荐

