C# Resharper说要将foreach转换为LINQ,但这有可能吗?
我有一个项目实体,它有一个导航属性,即地址列表。在搜索页面上,我允许用户一次按多个地址搜索项目。是否可以在一条语句中执行此操作,还是需要循环搜索的地址 目前我有以下代码,其中searchedAddresses是用于搜索项目的地址列表。在foreach循环中,我创建了一个查询,并在每次通过循环时将其与整个查询合并。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
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好:)