如何实现Entity Framework仅在非空查询字段上执行数据过滤
.NET Core MVC条件查询无输入时返回空的修复方案
问题场景
现有一个.NET Core MVC应用,负责向用户展示数据,支持按输入条件过滤,预期逻辑是:未传入任何筛选条件时返回全量实体数据。
为实现条件拼接,编写了如下IQueryable自定义扩展方法:
public static class QueryableEx { public static IQueryable<T> Where<T>( this IQueryable<T> @this, bool condition, Expression<Func<T, bool>> @where) { return condition ? @this.Where(@where) : @this; } }
控制器中对应的查询Action如下:
[HttpPost] public IActionResult query(QueryModel query) { List<CustomerModel> customers = new List<CustomerModel>(); var db = new DemoContext(); customers = db.Customers .Where(query.Name != null, x => x.Name == query.Name) .Where(query.Surname != null, x => x.Surname == query.Surname) .Where(query.Age != null, x => x.Age == query.Age) .ToList(); return View("Index", customers); }
当前单字段过滤可以正常生效,但所有输入字段均为空时,会返回空结果,和预期的返回全量数据逻辑不符。
涉及的模型定义如下:
查询参数模型:
public class QueryModel { public string Name {get;set; } public string Surname { get; set; } public uint Age { get; set; } }
客户实体模型:
public class CustomerModel { public int Id{get;set; } [Required] public string Name {get;set; } [Required] public string Surname { get; set; } [Required] [Range(18,110)] public uint Age { get; set; } [Required] public virtual AdressModel Adress { get; set; } [Required] public DateTime Created { get; set; } [Required] public virtual List<PurchaseModel> purchases { get; set; } }
问题根因
核心出在Age字段的类型定义上:
uint是非空值类型,默认值为0,永远不可能为null,因此原代码中query.Age != null的判断永远返回true,始终会执行x.Age == query.Age也就是x.Age == 0的过滤。- 而
CustomerModel的Age字段配置了[Range(18,110)]的校验规则,库中不存在年龄为0的客户数据,因此所有字段都不输入时,会过滤掉所有数据返回空结果。
另外字符串字段的判断也存在隐患:如果前端传入空字符串或纯空格内容,原!= null判断会误判为有筛选条件,去匹配姓名/姓氏为空的数据,大概率返回异常空结果。
修复方案
- 修改
QueryModel中的Age属性为可空值类型uint?,让未输入时的null判断可以正常生效 - 字符串字段的判断改用
string.IsNullOrWhiteSpace,兼容null、空串、纯空格的无效输入场景
修复后的QueryModel:
public class QueryModel { public string Name {get;set; } public string Surname { get; set; } // 改为可空值类型,未传入值时为null public uint? Age { get; set; } }
修复后的查询逻辑:
[HttpPost] public IActionResult query(QueryModel query) { var db = new DemoContext(); var customers = db.Customers .Where(!string.IsNullOrWhiteSpace(query.Name), x => x.Name == query.Name) .Where(!string.IsNullOrWhiteSpace(query.Surname), x => x.Surname == query.Surname) .Where(query.Age != null, x => x.Age == query.Age) .ToList(); return View("Index", customers); }
调整后,所有筛选字段都没有有效输入时,三个Where的条件判断都返回false,不会追加任何过滤语句,直接返回全量数据;输入任意有效筛选条件时,对应过滤逻辑正常生效。
内容的提问来源于stack exchange,提问作者Grazosi
相关产品推荐
相关产品推荐

