【问题标题】:Help Understanding Enumerable.Join Method帮助理解 Enumerable.Join 方法
【发布时间】:2010-03-13 19:03:35
【问题描述】:

昨天我posted this question 关于在 Join() 方法中使用 lambdas 来检查 2 个条件是否存在于 2 个实体中。我收到了关于这个问题的答案,效果很好。在阅读有关 Enumerable.Join() 方法的 MSDN 文章后,我想我会确切地了解发生了什么,但我不知道。有人可以帮我理解下面的代码中发生了什么(特别是 Join() 方法)吗?提前致谢。

if (db.TableA.Where( a => a.UserID == currentUser )
      .Join( db.TableB.Where( b => b.MyField == someValue ),
             o => o.someFieldID,
             i => i.someFieldID,
             (o,i) => o )
      .Any()) 
{
    //...
}

编辑: 具体来说,我很好奇最后 3 个参数,以及实际发生了什么。它们如何导致 Func(TOuter, TKey)、Func(TInner, TKey) 等的签名要求。

【问题讨论】:

    标签: c# .net asp.net linq


    【解决方案1】:

    连接语法是

    FirstTable.Join(SecondTable, FirstTableKeyExtractor, SecondTableKeyExtractor, Selector)
    

    所以你有两张桌子。您有一些两个表共有的键。您提供了两个密钥提取器,它们知道如何从表中的每一行中获取密钥。

    连接逻辑识别具有相同键的行对,每个表中的一个。

    然后这些行中的每一行都通过选择器运行以投影结果。

    这能回答你的问题吗?

    【讨论】:

    • 差不多。我知道第一个参数是一个实体(与这些条件匹配的表),但我很好奇其他 3 个参数是如何工作的。此时到底发生了什么:o => o.SomeFieldID, i => i.SomeFieldID, (o, i) => o
    • @lush - 第二个参数表示您要匹配原始表上的哪个字段(TableA.someFieldID),第三个参数表示您要匹配连接表上的哪个字段(@ 987654323@)。最后一个参数从这组新加入的表中表示,您正在选择什么......在这种情况下,这就是来自TableA 的所有内容。在您的代码中,您可以将o 替换为a,将i 替换为b,这样可能会更清晰。
    • 但是代码“o => o.SomeFieldID”如何转换为“TableA.SomeFieldID”?引擎盖下发生了什么?
    • 我已经更新了答案以涵盖 o => o.SomeFieldId 语法。
    【解决方案2】:

    连接说明。

    b = 第一个表的对象类型 o = 第一个表的对象类型 i = 第二个表的对象类型

    1. db.TableB.Where( b => b.MyField == someValue )这是第二个表的元素类型
    2. o => o.someFieldID第一张表的key
    3. i => i.someFieldID第二张表的键(会匹配第一张表的键)
    4. (o,i) => o 要返回的对象,在本例中为第一个表的对象类型。

    【讨论】:

      【解决方案3】:

      埃里克和尼克都提供了很好的答案。

      您还可以使用查询语法(与您在示例中使用的方法语法)编写 Linq 查询表达式:

      var query = from a in db.TableA 
                  join b in db.TableB on a.someFieldID equals b.someFieldID
                  where a.UserID == currentUser && b.MyField == someValue
                  select a;
      
              if (query.Any()) {
                  ...
              }
      

      更新:

      您似乎卡在 lambda 表达式上。这是一个像变量一样传递的函数。 lambda 表达式等效于匿名委托(或匿名方法,对我来说更笼统)。

      这是您使用 lambda 表达式作为委托的查询(当然,将 EntityType 替换为从 TableA 返回的实体类型):

      if (db.TableA.Where( delegate(EntityType a) { return a.UserID == currentUser; } ) 
        .Join( db.TableB.Where( delegate(EntityType b) { return b.MyField == someValue; } ), 
               delegate(EntityType o) { return o.somefieldId); },
               delegate(EntityType i) { return i.someFieldId); },
               delegate(EntityType o, EntityType i) { return o; }) 
        .Any())  
      

      { //... }

      注意:lambda 表达式的重要方面使其不仅仅是匿名方法的等价物。我建议您查看其他 SO 问题,并特别在线阅读有关 lambda 表达式的信息。它们允许以更简单和优雅的方式表达非常强大的想法。这是一个很深的话题,但基础知识很容易理解。它是一个可以像变量一样传递的函数,也可以作为其他函数的参数。

      【讨论】:

      • 是的,我之前确实是这样写的,后来意识到可以通过使用 lambdas 的 Join 方法来完成,我想我会挑战自己。我仍然相信这种方式会更清晰,并且可能会以这种方式实现解决方案,但我想先完全理解另一种技术。
      • 在您更新的示例中,第二个委托(EntityType o)不应该是委托(EntityType i)吗?
      • 是的,谢谢 Metro Smurf(我不敢相信这两个词一个接一个地出现,哈哈)。
      • 完美,鉴于我对隐式类型的理解以及迄今为止我对匿名方法和 lambda 表达式知之甚少,这正是我所寻找的。我特别感谢您的代码示例。谢谢。
      【解决方案4】:

      这个查询是说 join TableA to TableB where TableA.someFieldID == TableB.someFieldID 并从 TableA 中选择结果并查看是否有任何结果

      在 SQL 方面可以这样想,即使它不是 Linq-to-SQL...如果您熟悉 SQL,也许这更有意义:

      Select Count(*)
      From TableA a
           Join TableB b
             On a.someFieldID = b.someFieldID
      

      然后检查Count(*)是否> 0

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-14
        • 2012-09-01
        • 2011-01-15
        • 1970-01-01
        • 2011-09-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多