【问题标题】:Linq-to-Entities: LEFT OUTER JOIN with WHERE clause, calculation and projectionLinq-to-Entities:带有 WHERE 子句的 LEFT OUTER JOIN、计算和投影
【发布时间】:2013-06-24 04:24:28
【问题描述】:

我很难弄清楚如何将多列上的简单 SQL LEFT OUTER JOIN 和 where 子句转换为有效的 Linq-to-Entities 查询。只有两张桌子。我需要 Table1 中所有行的值,无论 Table2 中的匹配如何,但事实证明连接多个列很困难。我还需要在查询中做一个简单的计算,但也找不到。 SQL 中的查询如下所示:

select t1.tableid1,
t1.tableid2,
t1.fieldvalue1,
t2.fieldvalue2,
isnull(t2.fieldvalue2,0) / t1.fieldvalue1 as calcvalue
t1.fieldvalue1 - isnull(t2.fieldvalue2,0) as calcvalue2
from table1 t1
left outer join table2 t2 
    on t1.tableid1 = t2.tableid1
    and t1.tableid2 = t2.tableid2
    and t1.tableid3 = t2.tableid3
where t1.tableid1 = @somevalue

我可以进行单列左连接,但我似乎找不到多列的正确语法,更不用说不知道如何添加或减去列上的值。以下是我的最佳猜测,但我得到了一个 Type Expected 错误(在“new”之后和第一个左括号之前):

On New (t2.Field(Of String)("tableid1"), t2.Field(Of String)

最佳猜测:

Dim query = From t1 In dtTable1 _
                         Group Join t2 In dtTable2 _
                         On New (t2.Field(Of String)("tableid1"), t2.Field(Of String)("tableid2")) Equals _
                            (t1.Field(Of String)("tableid1"), t1.Field(Of String)("tableid2")) _
                         Into t2outer = Group _
                         From t2 In t2outer.DefaultIfEmpty() _
                         Select New With _
                        { _
                            .t1_tableid1 = t1.Field(Of String)("tableid1"), _
                            .t1_tableid2 = t1.Field(Of String)("tableid2"), _
                            .t1_fieldvalue1 = t1.Field(Of Integer)("fieldvalue1"))
                            .t2_fieldvalue2 = If(t2 Is Nothing, CType("0", Integer), t2.Field(Of Integer)("fieldvalue2"))
                        }

@Gert 这让我足够接近。我认为格式略有偏差,因为我必须添加大括号而不是括号,并且它在“Key”关键字和 id 之间放置了一个空格:

On New With {
                        Key .id1 = t2.Field(Of String)("tableid1"), _
                        Key .id2 = t2.Field(Of String)("tableid2")
                        } _
                    Equals _
                    New With {
                        Key .id1 = t1.Field(Of String)("tableid1"), _
                        Key .id2 = t1.Field(Of String)("tableid2")
                        } _

感谢 Gert,我能够按照 SQL 查询中的说明进行操作。请参阅下面的 SQL 查询的完整工作表示形式:

Dim query = From t1 In dtTable1 _
    Where (T1.Field(Of String)("fieldvalue1") = SOMEVALUE) _
     Group Join t2 In dtTable2 _
     On New (t2.Field(Of String)("tableid1"), t2.Field(Of String)("tableid2")) Equals _
        (t1.Field(Of String)("tableid1"), t1.Field(Of String)("tableid2")) _
     Into t2outer = Group _
     From t2 In t2outer.DefaultIfEmpty() _
     Select New With _
    { _
        .t1_tableid1 = t1.Field(Of String)("tableid1"), _
        .t1_tableid2 = t1.Field(Of String)("tableid2"), _
        .t1_fieldvalue1 = t1.Field(Of Integer)("fieldvalue1"))
        .t2_fieldvalue2 = If(t2 Is Nothing, CType("0", Integer), t2.Field(Of Integer)("fieldvalue2"))
        .calcvalue = If(t2.Field(Of Integer)("fieldvalue2") Is Nothing, CType("0", Integer), t2.Field(Of Integer)("fieldvalue2")) _
            / CType(t1.Field(Of String)("fieldvalue1"), Integer), 
        .calcvalue2 = CType(t1.Field(Of String)("fieldvalue1"), Integer) _
            - If(t2.Field(Of Integer)("fieldvalue2") Is Nothing, CType("0", Integer), t2.Field(Of Integer)("fieldvalue2")) _
    }

【问题讨论】:

    标签: vb.net linq linq-to-entities


    【解决方案1】:

    首先,如果你对多个字段进行分组,你是在比较匿名类型,所以部分

    On
       New (t2.Field(Of String)("tableid1"), t2.Field(Of String)("tableid2"))
    Equals
           (t1.Field(Of String)("tableid1"), t1.Field(Of String)("tableid2"))
    

    应该改成创建匿名类型的语法(和后面查询中使用的一样):

    On
      New With {.id1 = t2.Field(Of String)("tableid1"),
                .id2 = t2.Field(Of String)("tableid2")}
    Equals
      New With {.id1 = t1.Field(Of String)("tableid1"),
                .id2 = t1.Field(Of String)("tableid2")}
    

    但是

    在 C# 中这就足够了,因为对于匿名类型,C# 编译器使用基于 的相等性。然而,出于某种原因,在 VB 中这是不同的,它使用 reference 相等。所以Equals 总是false,因为第一个对象和第二个对象不是同一个对象。

    幸运的是,VB 有Key 关键字,可让您在比较匿名对象时指明要使用的属性。所以最终的语法是:

    On
      New With {Key .id1 = t2.Field(Of String)("tableid1"),
                Key. id2 = t2.Field(Of String)("tableid2")}
    Equals
      New With {Key .id1 = t1.Field(Of String)("tableid1"),
                Key .id2 = t1.Field(Of String)("tableid2")}
    

    【讨论】:

    • 这让我足够接近。我认为格式有点不对,
    • 非常感谢,这让我足够接近(请参阅我修改后的原始帖子)。我相信 vb.net 的格式可能会略有偏差?现在我应该在哪里添加我的 WHERE 子句,因为我需要它来过滤 table1 和 table2(如果它存在的话)。甚至可以在链接查询中进行简单的计算吗?即 t1.FieldValue1 - t2.FieldValue2 = CalculatedValue1
    • 通常对于嵌套的Wheres,最方便的方法是将查询语法与流式(方法)语法混合:dtTable1.Where(...)Group Join t2 In dtTable2.Where(...)。当然,您可以将计算出的属性放入投影中(=Select),但它们应该看起来像.t1_fieldvalue1 = t1.Field(...) - t1.Field(...)
    • 工作得非常出色。非常感谢。我将完整的代码添加到原始帖子中,以帮助将来的任何人。再次感谢格特!
    【解决方案2】:

    对于实体,您有一个容器并通过它们的名称评估您的表。此 where 子句按字段值过滤结果,并且可以与更多值连接。 {} 中的部分供您更改以匹配您的实体。此查询是 IEnumerable(Of {your entity})- 非常适合数据绑定。

    Dim query = model.{table name}.Where(Function(o) o.{column name} = {some value}).ToList()
    

    【讨论】:

    • 我很困惑......如果它是单列,我实际上可以让外连接工作,但是一旦我添加了多列,它就会出错。你能用我的例子详细说明一下吗?在阅读了几个 c# linq 查询后,我想到了尝试:“On New (t2.Field(Of String)("tableid1"), t2.Field(Of String)("tableid2")) Equals”位。我希望语法可能有点相似。
    • 如果您在创建模型之前在数据库中建立关系,您将拥有navigation properties。在这里,您可以通过table namefield 访问相关表。示例:如果表 CustomerOrders 相关,则您将拥有如下属性:Customers.Orders.OrderId 并且可以在上面的查询过滤器中使用它。
    猜你喜欢
    • 2011-04-26
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 2011-01-30
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    • 2010-11-26
    相关资源
    最近更新 更多