【问题标题】:Linq to entities - Query elements where List<string> property has at least an element that matches other element in an in memory listLinq to entity - 查询 List<string> 属性至少有一个元素与内存列表中的其他元素匹配的元素
【发布时间】:2021-11-25 05:10:52
【问题描述】:

问题的上下文

我的数据库中有一个实体 (Person),它与另一个实体 (Phone) 存在一对多关系。

    public class Person
    {
        [Key]
        public int Id { get; set; }
        .
        .
        .
        [ForeignKey("PersonId")]
        public virtual List<Phone> Phones { get; set; }
    }

    public class Phone
    {
        [Key]
        public int Id { get; set; }
        .
        .
        .
        public string PhoneNumber { get; set; }

        public int PersonId { get; set; }

        public virtual Person Person { get; set; }
    }

其次,我收到一个包含字符串列表的过滤器。

问题:

我正在尝试从数据库中获取至少具有与过滤器的任何电话号码匹配(通过类似)的电话号码的所有人员。

到目前为止,我已经尝试过:

var query = _dbContext.Person
                .Include(x => x.PhoneNumbers)
                .AsNoTracking();
                .Where(x => x.Phones
                             .Any(y => filter.Phones
                                             .Any(z => y.PhoneNumber.Contains(z))));

此查询引发错误:

无法翻译 LINQ 表达式 {my expression here}。以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。请参阅https://go.microsoft.com/fwlink/?linkid=2101038 了解更多信息。”

谢谢!

【问题讨论】:

  • 您不能在内存中集合上使用 EF Core LINQ 运算符,Contains 方法除外。 filter.Phones.Any 不可翻译。在这种情况下,只有动态谓词构建才能有所帮助。

标签: c# .net entity-framework linq


【解决方案1】:

如果您对记录的电话号码使用标准化格式(即去除所有分隔符并包含标准区号等),那么您可以格式化您的电话号码搜索列表以符合格式并使用:

.Where(x => x.Phones.Any(y => filter.Phones.Contains(y.PhoneNumber)));

问题是您不能对内存中的集合应用 Linq2Entity Any。您可以对集合使用Contains,但电话号码必须完全匹配。 (所以没有内部LIKE 类型比较)

如果您有合理数量的搜索电话号码并希望在电话号码中进行 LIKE 类型搜索,那么您可以利用 LinqKit 的 PredicateBuilder 来准备合适的条件。这需要将查询标记为“可扩展”,以便构建动态谓词。

var query = _dbContext.Person
    .Include(x => x.PhoneNumbers)
    .AsNoTracking()
    .AsExpandable();

if (filter.Phones.Any())
{
    var predicate = PredicateBuilder.New<Person>();
    foreach(var phone in filter.Phones)
        predicate = predicate.Or(x => x.Phones.Any(p => p.Contains(phone)));
    query = query.Where(predicate);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 2012-07-11
    • 1970-01-01
    • 2023-02-12
    • 1970-01-01
    • 2018-04-15
    相关资源
    最近更新 更多