C# Resharper说要将foreach转换为LINQ,但这有可能吗?

C# Resharper说要将foreach转换为LINQ,但这有可能吗?,c#,linq,linq-to-entities,C#,Linq,Linq To Entities,我有一个项目实体,它有一个导航属性,即地址列表。在搜索页面上,我允许用户一次按多个地址搜索项目。是否可以在一条语句中执行此操作,还是需要循环搜索的地址 目前我有以下代码,其中searchedAddresses是用于搜索项目的地址列表。在foreach循环中,我创建了一个查询,并在每次通过循环时将其与整个查询合并。Resharper说foreach可以使用LINQ重写,如果可能的话,我想取消查询的联合 foreach (AddressModel address in searchedAddress

我有一个项目实体,它有一个导航属性,即地址列表。在搜索页面上,我允许用户一次按多个地址搜索项目。是否可以在一条语句中执行此操作,还是需要循环搜索的地址

目前我有以下代码,其中searchedAddresses是用于搜索项目的地址列表。在foreach循环中,我创建了一个查询,并在每次通过循环时将其与整个查询合并。Resharper说foreach可以使用LINQ重写,如果可能的话,我想取消查询的联合

foreach (AddressModel address in searchedAddresses)
{
    var query = _projectRepository.Get().Where(p => p.Addresses.Any(a => a.StreetName.ToLower().StartsWith(address.StreetName.ToLower())));

    union = (union == null ? query : union.Union(query));
}
我试着把它写成一句话,但不起作用:

var query = _projectRepository.Get().Where(p => p.Addresses.Any(a => searchedAddresses.Any(sa => a.StreetName.ToLower().StartsWith(sa.StreetName.ToLower())));
执行此操作时,会出现以下错误:“无法创建“EPIC.WebAPI.Models.AddressModel”类型的常量值。此上下文中仅支持基元类型或枚举类型。”

我假设这是因为searchedAddresses.Any()部分。有人知道如何编写这个查询,这样我就不需要遍历地址并合并查询了吗?或者这样做可以吗

谢谢


编辑:将ToLower和StartsWith添加到我最初忘记的第二个查询中。

我怀疑最简单的方法是为您首先搜索的街道名称创建一个
列表-我希望这些名称可以转换:

var searchedStreets = searchedAddresses.Select(x => x.StreetName).ToList();
var query = projectRepository
      .Get()
      .Where(p => p.Addresses.Any(a => searchStreets.Contains(a.StreetName)));
如果
列表
不起作用,可能值得尝试
字符串[]
。(只需将
ToList
更改为
ToArray

每当您必须“uinion”给定集合的所有结果时,您可以用语句替换Foreach

searchedAddresses
    .SelectMany(address =>
        _projectRepository
        .Get()
        .Where(p => p.Addresses.Any(a => 
            a.StreetName
            .ToLower()
            .StartsWith(address.StreetName.ToLower()))))
    .Distinct();
这将对每个结果进行迭代,对每个单独的子查询进行联合迭代,产生相同的效果(可能会提高性能)

编辑:复制/粘贴问题代码时使用了错误的lambda参数。修正了。
编辑:与Union不同,SelectMany不会删除重复项,因此我相应地更新了代码

我怀疑ReSharper希望您执行以下操作:

var union = searchedAddresses
    .Select(address => _projectRepository.Get()
        .Where(p => p.Addresses.Any(a =>
            a.StreetName.ToLower().StartsWith(address.StreetName.ToLower()))))
    .Aggregate(
        (something)null,
        (union, query) => union.Union(query));
其中
某物
与原始代码中的
联合
类型相同

(如果它告诉您可以将循环转换为单个查询,那么它也应该给您自动执行的选项。)


我自己并不认为这一点特别干净。

这仍然会针对每个地址对数据库执行查询,除非
searchedAddresses
是同一上下文中的
IQueryable
Union
删除重复项
SelectMany
没有。@Rawling这部分我不知道,它会相应地更新答案,当然,如果
SearchedAddresss
恰好是同一上下文中的
IQueryable
,那么您可以删除
ToList
,进行一次数据库往返,并且仍然有一个有效的查询。在这方面可能会更有效。当然,如果
searchedAddresses
不是来自同一上下文的查询,那么这就是您所能做的最好的了。我认为我的示例简化得太多了。我在上面只基于StreetName进行匹配,但实际上我想根据StreetName、StreetNumber和ZipCode进行匹配,这不允许我使用searchStreets.Contains()方法。@Buffer:不清楚你的意思-如果你想匹配其中任何一种,那么你可以使用三个不同的数组并使用
x.Contains(…)| | y.Contains(…)| | z.Contains(…)
。但是,是的,听起来你简化得太多了:(我不知道resharper能帮我做这件事。现在我知道了。谢谢。这篇文章,就像Aravol的一样,有一个问题,它最终会对每个地址执行一个查询,而Jon的解决方案只执行一个查询,total。@Servy:当我使用这个方法时,我只看到一个查询,它将所有被搜索的地址合并在一起。@Servy我只是回复解释ReSharper想做什么。ReSharper没有Jon好:)