【问题标题】:Need to retrieve List of items containing subitems matched with another List需要检索包含与另一个列表匹配的子项的项目列表
【发布时间】:2010-10-28 00:45:05
【问题描述】:

情况:

我有一些具有特定技能的人,他们可以/可能属于多个领域。 技能链接在单独的表格中,区域也是如此。

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

结果列表:

List<Person> peopleWithRightSkills

在每个 [Person] 对象上,我至少链接了 1 个地址,但与 [Person] 相关的地址可以更多

我还有另一个清单:

List<PostalCode> acceptedPostalcodes

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

内的地址的 peopleWithRightSkills

我一直在研究 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

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

希望对此有一个很好的答案,因为我已经被困了几个小时,试图找出使用什么语法来解决这个更漂亮、性能更低的问题。

【问题讨论】:

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


    【解决方案1】:
    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&lt;int&gt; 中的每个元素转换为参数。然后它将Contains方法调用翻译成TSqlIN子句。

    请注意,LinqToSql 很乐意将任意数量的元素转换为参数(我自己见过 50k),然而 SqlServer 只接受约 2000 个参数。如果您的列表包含的元素多于您需要分解这些列表的元素。如果你有 1500 人有合适的技能和 1000 个接受的邮政编码,你需要向 SQL Server 发送 2500 个参数,这 400 太多了,它会给你一个 SqlException。

    【讨论】:

    • 如果您实际使用的是 LINQ-to-SQL 并且您还没有在客户端上处理所有内容,那么这肯定是正确的方法。
    • 是的,所以这样做的目的是避免从不加载地址。
    • 我在这里感觉完全是新手。 :o) 但是谢谢,那我也试试这个。我不确定你最后一句带参数的意思。你能详细说明一下吗?
    • 这是一个纯网络应用程序,所有数据都来自 SQL-server。因此,进行比较所需的数据越少,确实越好!
    • 刚刚检查了我的记录,目前作为测试,我们有大约 1300 个邮政编码和至少 1200 人,而且这个数字还会增长。嗯。我想我最好坚持我的第一次尝试,将人员和邮政编码都取出一次,然后尝试在内存中“过滤/匹配”它们。当我有东西时我会发布。
    【解决方案2】:

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

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

    恐怕我并没有真正理解您通过展示表格结构在问题的其余部分中的意思,所以我希望我没有错过您所做工作的一些微妙之处。

    编辑:由于您似乎对使用 LINQ 做事感兴趣,因此您将如何从接受 PostalCodes 的 peopleWithRightSkills 中挑选出元素:

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

    【讨论】:

    • 我希望有 .Contains 或 .SelectMany 的东西?这种方法真的没有解决方案吗?
    • 当然,您可以使用acceptedPostalCodes.Contains(address) 而不是循环。不过,这不会对性能产生任何影响。
    • 感谢您的回答和支持 - 以及如此快速的回复!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多