需要检索包含与另一个List匹配的子项的项目列表

时间:2009-05-21 19:08:09

标签: c# linq-to-sql collections linq

情况:

我有一些具有某些技能的人,他们可能/可能属于多个领域。 这些技能在单独的表格中相关联,区域也是如此。

我从人员列表中选择所有匹配每个技能的人员并将其添加到列表中,我可以使用Distinct()来确保他们不会出现两次。

结果列表:

List<Person> peopleWithRightSkills

在每个[Person]对象上,我至少链接了一个地址,但是它们可以与[Person]

中的关系更多

我有另一个清单:

List<PostalCode> acceptedPostalcodes

现在我需要比较和过滤那些拥有地址的邮政编码在 acceptedPostalcodes

内的地址的人们。

我一直在调查Lambda表达式,SelectMany以及其他解决方案,但是现在,我只有一个选项,我认为是做事的“旧式”,即贯穿每个人和每个人的比赛她/他的地址列表与邮政编码列表。并为每个匹配,然后将其添加到:

List<Person> matchedPeople

表格概述(缩短所需的详细信息)

[Table:Person]
int:ID (primary)
string:FirstName
string:LastName

[Table:Address]
int:Person_ID (foreign key to Person)
int:PostalCode_ID (foreing key to PostalCode)
string:StreetName

[Table:PostalCode]
int:ID
string:CityName

当我看到问题时,它只是一个“短名单pr。人”(最少1个,可能最多10个地址),我需要将这个地址列表与每个人的“有效邮政编码列表”进行比较。

希望对此有一个很好的答案,因为我已经被困了几个小时了,试图弄清楚用什么语法来解决这个问题更加美好而且表现更差。

2 个答案:

答案 0 :(得分:4)

List<int> peopleIDs = peopleWithRightSkills.Select(p => p.ID).ToList();
List<int> postalIDs = acceptedPostalCodes.Select(c => c.ID).ToList();

var query = db.Persons
  .Where(p => peopleIDs.Contains(p.ID)
  .Where(p => p.Addresses.Any(a => postalIDs.Contains(a.PostalCode_ID))
  );

LinqToSql会将List<int>中的每个元素转换为参数。然后它会将Contains方法调用转换为TSql IN子句。

请注意,LinqToSql会很乐意将所需的元素转换为参数(我自己看过50k),然而 SqlServer只接受~2000个参数。如果您的列表包含的元素多于您需要拆分这些列表的元素。如果您有1500名具有正确技能的人员和1000名已接受的邮政编码,则需要向SQL Server发送2500个参数,这些参数为400,并且会给您一个SqlException。

答案 1 :(得分:2)

假设有很多人,acceptedPostalCodes不应该是一个列表;它应该是排序列表/二进制树或哈希表,具体取决于有多少代码。这本身就足以让您获得数量级的性能提升。然后,是的,如果他们的地址在acceptedPostalCodes,请检查每个人并接受该人。

没有更好的方法可以做到这一点,除非你有奇怪的数据(即如果反复出现相同的地址,你可以在某种辅助结构中缓存这些地址的结果。)

我担心通过提供表格结构,我真的不明白你在问题的其余部分,所以我希望我不会错过你正在做的事情的一些微妙。

编辑:既然你似乎对使用LINQ做事感兴趣,那么你就可以从peopleWithRightSkills中挑选出已经接受过邮政编码的元素:

var matchedPeople =
peopleWithRightSkills.Where(p => acceptablePostalCodes.Contains(p.Address));