Asp.Net Core EF报错:LINQ查询参数表达式求值异常解决问询
问题描述
我正在使用Entity Framework查询数据库,通过searchOne、searchTwo、searchThree、searchFour四个条件进行搜索,代码如下:
public async Task<List<ClassName>> Search(string searchOne, string searchTwo, string searchThree, string searchFour) { if (!String.IsNullOrEmpty(searchOne) || !String.IsNullOrEmpty(searchTwo) || !String.IsNullOrEmpty(searchThree) || !String.IsNullOrEmpty(searchFour)) { return await _context.Class.Include(x => x.ClassContainForeignKey) .OrderBy(x => x.ID) .Where(x => x.SearchOne.ToLower().Contains(String.IsNullOrEmpty(searchOne.ToLower()) ? "" : searchOne.ToLower()) && x.SearchTwo.ToLower().Contains(String.IsNullOrEmpty(searchTwo.ToLower()) ? "" : searchTwo.ToLower()) && x.SearchThree.ToLower().Contains(String.IsNullOrEmpty(searchThree.ToLower()) ? "" : searchThree.ToLower()) && x.SearchFour.ToLower().Contains(String.IsNullOrEmpty(searchFour.ToLower()) ? "": searchFour.ToLower())).ToListAsync(); } else { return await _context.Class.Include(x => x.ClassContainForeignKey).OrderBy(x => x.ID).ToListAsync(); } }
但代码无法正常运行,调试发现错误来自返回数据的代码段:
return await _context.Class.Include(x => x.ClassContainForeignKey) .OrderBy(x => x.ID) .Where(x => x.SearchOne.ToLower().Contains(String.IsNullOrEmpty(searchOne.ToLower()) ? "" : searchOne.ToLower()) && x.SearchTwo.ToLower().Contains(String.IsNullOrEmpty(searchTwo.ToLower()) ? "" : searchTwo.ToLower()) && x.SearchThree.ToLower().Contains(String.IsNullOrEmpty(searchThree.ToLower()) ? "" : searchThree.ToLower()) && x.SearchFour.ToLower().Contains(String.IsNullOrEmpty(searchFour.ToLower()) ? "": searchFour.ToLower())).ToListAsync();
出现错误:
One or more errors occurred (An exception was thrown while attempting to evaluate a LINQ query parameter expression. See the inner exception for more information. To show additional information call 'DbContextOptionsBuilder.EnableSensitiveDataLogging'.)
现寻求帮助:
- 如何使用Entity Framework Core而非LINQ解决该异常问题?
- 如何通过单个if语句,使用Entity Framework Core实现多条件搜索?
解决方案
1. 修复异常问题(EF Core实现)
报错核心原因是在LINQ表达式中直接对可能为null的参数调用ToLower(),当searchOne这类参数为null时,searchOne.ToLower()会抛出空引用异常,而EF Core无法将这种运行时异常转换为SQL表达式。
正确做法是先在LINQ表达式外部处理参数,再构建查询:
public async Task<List<ClassName>> Search(string searchOne, string searchTwo, string searchThree, string searchFour) { // 初始化基础查询 var query = _context.Class.Include(x => x.ClassContainForeignKey).OrderBy(x => x.ID); // 逐个处理非空搜索条件,动态添加过滤 if (!string.IsNullOrEmpty(searchOne)) { var lowerSearchOne = searchOne.ToLower(); query = query.Where(x => x.SearchOne.ToLower().Contains(lowerSearchOne)); } if (!string.IsNullOrEmpty(searchTwo)) { var lowerSearchTwo = searchTwo.ToLower(); query = query.Where(x => x.SearchTwo.ToLower().Contains(lowerSearchTwo)); } if (!string.IsNullOrEmpty(searchThree)) { var lowerSearchThree = searchThree.ToLower(); query = query.Where(x => x.SearchThree.ToLower().Contains(lowerSearchThree)); } if (!string.IsNullOrEmpty(searchFour)) { var lowerSearchFour = searchFour.ToLower(); query = query.Where(x => x.SearchFour.ToLower().Contains(lowerSearchFour)); } return await query.ToListAsync(); }
该方案优势:
- 提前处理参数,避免空引用异常
- EF Core可正确解析表达式,生成高效SQL
- 逻辑拆分清晰,便于后续维护
2. 单个if语句实现多条件搜索
若需用单个if语句,可先安全预处理所有参数,再构建统一过滤条件:
public async Task<List<ClassName>> Search(string searchOne, string searchTwo, string searchThree, string searchFour) { var query = _context.Class.Include(x => x.ClassContainForeignKey).OrderBy(x => x.ID); if (!string.IsNullOrEmpty(searchOne) || !string.IsNullOrEmpty(searchTwo) || !string.IsNullOrEmpty(searchThree) || !string.IsNullOrEmpty(searchFour)) { // 安全处理参数,避免空引用 var s1 = searchOne?.ToLower() ?? ""; var s2 = searchTwo?.ToLower() ?? ""; var s3 = searchThree?.ToLower() ?? ""; var s4 = searchFour?.ToLower() ?? ""; // 构建多条件过滤:参数为空则该条件自动生效(不过滤),否则执行匹配 query = query.Where(x => (string.IsNullOrEmpty(s1) || x.SearchOne.ToLower().Contains(s1)) && (string.IsNullOrEmpty(s2) || x.SearchTwo.ToLower().Contains(s2)) && (string.IsNullOrEmpty(s3) || x.SearchThree.ToLower().Contains(s3)) && (string.IsNullOrEmpty(s4) || x.SearchFour.ToLower().Contains(s4))); } return await query.ToListAsync(); }
补充优化建议
若使用EF Core 5及以上版本,推荐用EF.Functions.Like替代ToLower().Contains(),可利用数据库索引优化查询性能,同时避免大小写转换的额外开销:
query = query.Where(x => EF.Functions.Like(x.SearchOne, $"%{searchOne}%"));
注意:Like的大小写匹配规则取决于数据库列的排序规则,若需强制不区分大小写,可调整对应列的排序规则为不区分大小写类型。
内容的提问来源于stack exchange,提问作者ali

