如何在Entity Framework Core 6中实现带可选Where条件的查询
在EF Core 6中实现可选WHERE条件查询的原生方案
针对将内嵌SQL的可选WHERE逻辑迁移到EF Core 6的需求,以下是几种基于EF Core原生功能的可行方案,无需依赖第三方工具:
方案1:基于实体对象的自动筛选
如果你的筛选条件和实体结构匹配,可以通过反射动态生成筛选表达式,自动忽略空值或默认值属性,实现类似"传入实体作为筛选条件"的效果。
扩展方法实现
using System.Linq.Expressions; public static class QueryableExtensions { public static IQueryable<T> WhereByNonEmptyProperties<T>(this IQueryable<T> query, T filter) where T : class { if (filter == null) return query; var parameter = Expression.Parameter(typeof(T), "entity"); Expression combinedCondition = null; foreach (var property in typeof(T).GetProperties()) { var propertyValue = property.GetValue(filter); if (propertyValue == null) continue; // 跳过值类型的默认值(如int的0、bool的false,可根据业务调整) if (property.PropertyType.IsValueType && Equals(propertyValue, Activator.CreateInstance(property.PropertyType))) { continue; } // 构建属性等于值的表达式 var propertyAccess = Expression.Property(parameter, property.Name); var constantValue = Expression.Constant(propertyValue); var equalsExpr = Expression.Equal(propertyAccess, constantValue); combinedCondition = combinedCondition == null ? equalsExpr : Expression.AndAlso(combinedCondition, equalsExpr); } if (combinedCondition != null) { var filterLambda = Expression.Lambda<Func<T, bool>>(combinedCondition, parameter); query = query.Where(filterLambda); } return query; } }
用法示例
假设你有Customer实体:
public class Customer { public int Id { get; set; } public string Name { get; set; } public int? Age { get; set; } public string City { get; set; } }
查询时只需构造筛选实体,空属性会被自动忽略:
var filter = new Customer { Name = "Alice", City = "London" }; var customers = _dbContext.Customers .WhereByNonEmptyProperties(filter) .ToList();
这会生成等价于WHERE Name = 'Alice' AND City = 'London'的SQL。
方案2:直接传入表达式树
如果需要支持复杂的自定义筛选逻辑,直接让调用方传入Expression<Func<T, bool>>类型的条件,这是EF Core最原生的用法,灵活性最高。
实现代码
public class CustomerRepository { private readonly AppDbContext _dbContext; public CustomerRepository(AppDbContext dbContext) { _dbContext = dbContext; } public IQueryable<Customer> GetCustomers(Expression<Func<Customer, bool>> filter = null) { var query = _dbContext.Customers.AsQueryable(); if (filter != null) { query = query.Where(filter); } return query; } }
用法示例
调用时可以传入任意复杂的条件:
// 查询年龄大于30且来自纽约的客户 var customers = _customerRepository.GetCustomers( x => x.Age > 30 && x.City == "New York" && x.CreatedDate > DateTime.Now.AddMonths(-6) ).ToList(); // 不传条件则查询全部 var allCustomers = _customerRepository.GetCustomers().ToList();
方案3:链式拼接筛选条件
对于已知固定筛选参数的场景,直接通过链式调用Where方法拼接条件,代码直观且性能最优,无需反射或表达式树动态生成。
实现代码
public IQueryable<Customer> GetFilteredCustomers(string name = null, int? age = null, string city = null) { var query = _dbContext.Customers.AsQueryable(); if (!string.IsNullOrWhiteSpace(name)) { query = query.Where(x => x.Name.Contains(name)); } if (age.HasValue) { query = query.Where(x => x.Age == age.Value); } if (!string.IsNullOrWhiteSpace(city)) { query = query.Where(x => x.City == city); } return query; }
用法示例
// 只按城市筛选 var londonCustomers = GetFilteredCustomers(city: "London").ToList(); // 按姓名和年龄筛选 var alice30 = GetFilteredCustomers(name: "Alice", age: 30).ToList();
方案选择建议
- 若筛选条件与实体结构高度匹配,优先用方案1,简化调用方代码。
- 若需要支持复杂、灵活的自定义条件,选择方案2。
- 若筛选参数固定且明确,用方案3,代码可读性和性能最佳。
内容的提问来源于stack exchange,提问作者Ken
相关产品推荐
相关产品推荐

