EF Core如何在Where条件中动态切换运算符以避免代码重复?
优化冗余的动态过滤代码
核心思路
重复代码的根源在于相同字段的非空判断逻辑+不同的字符串比较方式,我们可以把比较逻辑抽离成可动态切换的逻辑单元,再用通用方法统一处理每个字段的过滤,彻底消除重复代码。
方案一:适用于内存集合或允许客户端评估的场景
通过委托封装比较逻辑,用通用方法处理单个字段的过滤:
// 1. 根据比较类型获取对应的字符串比较委托 private Func<string, string, bool> GetComparisonLogic(ETipoConfronto tipoConfronto) { return tipoConfronto switch { ETipoConfronto.Uguale => (fieldVal, inputVal) => fieldVal == inputVal, ETipoConfronto.Inizia => (fieldVal, inputVal) => fieldVal.StartsWith(inputVal), ETipoConfronto.Contiene => (fieldVal, inputVal) => fieldVal.Contains(inputVal), _ => throw new ArgumentOutOfRangeException(nameof(tipoConfronto), "不支持的比较类型") }; } // 2. 通用过滤方法:处理字段非空判断+过滤逻辑 private IQueryable<T> ApplyFieldFilter<T>(IQueryable<T> query, string inputValue, Func<T, string> fieldSelector, Func<string, string, bool> comparison) { if (!string.IsNullOrEmpty(inputValue)) { query = query.Where(item => comparison(fieldSelector(item), inputValue)); } return query; } // 3. 简化后的主逻辑 var comparisonLogic = GetComparisonLogic(request.TipoConfronto); query = ApplyFieldFilter(query, request.Cognome, x => x.Cognome, comparisonLogic); query = ApplyFieldFilter(query, request.Nome, x => x.Nome, comparisonLogic); query = ApplyFieldFilter(query, request.CodFisc, x => x.CodFisc, comparisonLogic);
方案二:适用于EF Core等需要数据库端评估的场景
如果是EF Core的IQueryable,直接用委托会触发客户端过滤(性能损耗),需要改用表达式树确保过滤逻辑在数据库执行:
// 1. 根据比较类型获取对应的表达式树 private Expression<Func<string, string, bool>> GetComparisonExpression(ETipoConfronto tipoConfronto) { return tipoConfronto switch { ETipoConfronto.Uguale => (fieldVal, inputVal) => fieldVal == inputVal, ETipoConfronto.Inizia => (fieldVal, inputVal) => fieldVal.StartsWith(inputVal), ETipoConfronto.Contiene => (fieldVal, inputVal) => fieldVal.Contains(inputVal), _ => throw new ArgumentOutOfRangeException(nameof(tipoConfronto), "不支持的比较类型") }; } // 2. 通用过滤方法:组合表达式树,避免客户端评估 private IQueryable<T> ApplyFieldFilter<T>(IQueryable<T> query, string inputValue, Expression<Func<T, string>> fieldSelector, Expression<Func<string, string, bool>> comparisonExpr) { if (string.IsNullOrEmpty(inputValue)) return query; // 构建表达式:item => comparisonExpr(fieldSelector(item), inputValue) var parameter = Expression.Parameter(typeof(T), "item"); var fieldExpr = Expression.Invoke(fieldSelector, parameter); var inputConst = Expression.Constant(inputValue); var bodyExpr = Expression.Invoke(comparisonExpr, fieldExpr, inputConst); var filterLambda = Expression.Lambda<Func<T, bool>>(bodyExpr, parameter); return query.Where(filterLambda); } // 3. 简化后的主逻辑 var comparisonExpr = GetComparisonExpression(request.TipoConfronto); query = ApplyFieldFilter(query, request.Cognome, x => x.Cognome, comparisonExpr); query = ApplyFieldFilter(query, request.Nome, x => x.Nome, comparisonExpr); query = ApplyFieldFilter(query, request.CodFisc, x => x.CodFisc, comparisonExpr);
额外优化:批量处理字段
如果后续字段数量增加,可将字段选择器和输入值封装为集合,批量遍历处理:
var filters = new List<(string InputValue, Expression<Func<T, string>> FieldSelector)> { (request.Cognome, x => x.Cognome), (request.Nome, x => x.Nome), (request.CodFisc, x => x.CodFisc) }; var comparisonExpr = GetComparisonExpression(request.TipoConfronto); foreach (var (inputVal, selector) in filters) { query = ApplyFieldFilter(query, inputVal, selector, comparisonExpr); }
内容的提问来源于stack exchange,提问作者skysurfer
相关产品推荐
相关产品推荐

