Linq to Entities如何筛选关联Phone号码匹配内存列表的Person实体
报错原因
你当前写法的嵌套Any语法中,内层Any需要遍历内存中的筛选手机号列表,EF Core暂不支持该类嵌套内存集合遍历的翻译,因此抛出无法转换为SQL的异常。
解决方案
方案1:拆分查询(无需第三方依赖,EF Core全版本兼容)
先查符合手机号筛选条件的PersonId集合,再关联查询Person实体,该写法可被EF Core正常翻译为SQL:
// 边界处理:如果筛选手机号列表为空,可根据业务需求决定是查全量还是返回空 if (!filter.Phones?.Any() ?? true) { // 示例逻辑:无筛选条件时返回空 return Enumerable.Empty<Person>().ToList(); } // 第一步:查询所有符合手机号匹配规则的PersonId var qualifiedPersonIds = _dbContext.Phones .Where(phone => filter.Phones.Any(filterNum => phone.PhoneNumber.Contains(filterNum))) .Select(phone => phone.PersonId) .Distinct(); // 第二步:通过PersonId查询对应的Person实体,按需加载关联的Phone var result = await _dbContext.Person .Include(x => x.Phones) .AsNoTracking() .Where(person => qualifiedPersonIds.Contains(person.Id)) .ToListAsync();
方案2:动态拼接表达式树(性能更优,单条SQL查询)
可以通过LINQKit库的PredicateBuilder动态拼接匹配条件,无需拆分查询:
- 先安装对应EF Core版本的NuGet包
LinqKit.Microsoft.EntityFrameworkCore - 代码示例:
if (!filter.Phones?.Any() ?? true) { return Enumerable.Empty<Person>().ToList(); } // 构建Phone的匹配条件:只要有一个筛选号码匹配就成立 var phoneMatchPredicate = PredicateBuilder.New<Phone>(); foreach (var filterNum in filter.Phones) { phoneMatchPredicate = phoneMatchPredicate.Or(phone => phone.PhoneNumber.Contains(filterNum)); } var result = await _dbContext.Person .Include(x => x.Phones) .AsNoTracking() .Where(person => person.Phones.AsQueryable().Any(phoneMatchPredicate)) .AsExpandable() // 展开表达式树,供EF Core翻译 .ToListAsync();
注意事项
你原代码中Include(x => x.PhoneNumbers)的导航属性名和实体定义的Phones不一致,实际使用时需要修正为对应属性名,避免映射错误。
内容的提问来源于stack exchange,提问作者Iry Centeno
相关产品推荐
相关产品推荐

