如何为Linq与Entity Framework编写日期范围筛选扩展方法
实现代码
你可以通过原生表达式树构造过滤逻辑,无需依赖第三方库,EF可直接解析生成对应SQL,完整实现如下:
using System.Linq.Expressions; private static IQueryable<T> FilterOnCorrectSearchDateTime<T>(this IQueryable<T> efQueryable, Expression<Func<T, DateTime>> datePropertySelector, DateTime? dateFrom, DateTime? dateTo) { // 无过滤条件直接返回原查询 if (!dateFrom.HasValue && !dateTo.HasValue) return efQueryable; var parameter = datePropertySelector.Parameters[0]; var propertyAccess = datePropertySelector.Body; Expression filterCondition = null; // 构造起始日期过滤 if (dateFrom.HasValue) { var fromConst = Expression.Constant(dateFrom.Value, typeof(DateTime)); filterCondition = Expression.GreaterThanOrEqual(propertyAccess, fromConst); } // 构造结束日期过滤 if (dateTo.HasValue) { var toConst = Expression.Constant(dateTo.Value, typeof(DateTime)); var toCondition = Expression.LessThanOrEqual(propertyAccess, toConst); filterCondition = filterCondition == null ? toCondition : Expression.AndAlso(filterCondition, toCondition); } var filterLambda = Expression.Lambda<Func<T, bool>>(filterCondition, parameter); return efQueryable.Where(filterLambda); }
如果你的实体存在可空DateTime?类型的日期字段,可以新增以下重载适配:
private static IQueryable<T> FilterOnCorrectSearchDateTime<T>(this IQueryable<T> efQueryable, Expression<Func<T, DateTime?>> datePropertySelector, DateTime? dateFrom, DateTime? dateTo) { if (!dateFrom.HasValue && !dateTo.HasValue) return efQueryable; var parameter = datePropertySelector.Parameters[0]; var propertyAccess = datePropertySelector.Body; // 先过滤可空字段非空的情况 var hasValueCondition = Expression.Equal( Expression.Property(propertyAccess, nameof(DateTime.HasValue)), Expression.Constant(true)); var valueAccess = Expression.Property(propertyAccess, nameof(DateTime.Value)); Expression filterCondition = hasValueCondition; if (dateFrom.HasValue) { var fromConst = Expression.Constant(dateFrom.Value, typeof(DateTime)); var fromCondition = Expression.GreaterThanOrEqual(valueAccess, fromConst); filterCondition = Expression.AndAlso(filterCondition, fromCondition); } if (dateTo.HasValue) { var toConst = Expression.Constant(dateTo.Value, typeof(DateTime)); var toCondition = Expression.LessThanOrEqual(valueAccess, toConst); filterCondition = Expression.AndAlso(filterCondition, toCondition); } var filterLambda = Expression.Lambda<Func<T, bool>>(filterCondition, parameter); return efQueryable.Where(filterLambda); }
调用方式和你预期的完全一致:
EFquerable = EFquerable.FilterOnCorrectSearchDateTime(s=>s.PlannedEndDate, searchCriteria.PlannedEndDateFrom, searchCriteria.PlannedEndDateTo);
额外注意事项
- 你原有代码存在逻辑错误:双条件判断中
d.PlannedEndDate > searchCriteria.PlannedEndDateTo写反,会导致范围过滤完全失效,上述实现默认使用包含边界的比较(>=/<=),如果业务需要开闭区间可自行调整比较方法。 - 建议增加入参校验:如果传入的
dateFrom晚于dateTo,可直接抛出参数异常或跳过过滤,避免生成无效查询返回空结果。 - 该实现完全兼容多日期字段叠加过滤,不会互相干扰,EF解析生成的SQL和手写Where的效果完全一致,无性能损耗。
内容的提问来源于stack exchange,提问作者Jerker Pihl
相关产品推荐
相关产品推荐

