【问题标题】:Linq-to-Entities: LEFT OUTER JOIN with WHERE clause and projectionLinq-to-Entities:带有 WHERE 子句和投影的 LEFT OUTER JOIN
【发布时间】:2011-04-26 23:24:10
【问题描述】:

我花了很长时间弄清楚如何将带有两个条件 where 子句的简单 SQL LEFT OUTER JOIN 转换为有效的 Linq-to-Entities 查询。只有两张桌子。我需要 Table1 中所有行的值,无论 Table2 中的匹配项如何,但 WHERE 子句使用 Table2 中的字段。在 SQL 中,这两个参数是 Table2WhereColumn1 和 Table2WhereColumn2,查询(有效)如下所示:

SELECT t1.Table1Id,
    t1.FieldDescription, 
    t2.FieldValue
FROM Table1 t1 WITH (NOLOCK)
LEFT JOIN Table2 t2 WITH (NOLOCK) ON t1.Table1Id = t2.Table1Id
WHERE (t2.Table2WhereColumn1 = @someId OR t2.Table2WhereColumn1 IS NULL)
AND (t2.Table2WhereColumn2 = @someOtherId OR t2.Table2WhereColumn2 IS NULL)
ORDER BY t1.OrderByColumn

我尝试过将Group Join 与DefaultIfEmpty() 一起使用,以及隐式连接(没有实际的Join 关键字),但我只获取表2 中具有值的项目的行。我确信这不会有帮助,但这是我一直在尝试但不起作用的 Linq 示例:

Public Shared Function GetProfilePreferencesForCedent(ByVal dc As EntityContext, _
                                                      ByVal where1 As Int32, _
                                                      ByVal where2 As Int32) _
                                                  As IQueryable(Of ProjectedEntity)
    Return From t1 In dc.Table1
           Group Join t2 In dc.Table2 _
                On t1.Table1Id Equals t2.Table1Id _
                Into t2g1 = Group _
           From t2gx In t2g1.DefaultIfEmpty(Nothing)
           Where (t2gx.Table2Where1 = where1 Or t2gx.Table2Where1 = Nothing) _
                And (t2gx.Table2Where2 = where2 Or t2gx.Table2Where2 = Nothing)
           Order By t1.SortOrder
           Select New ProjectedEntity With {
               .Table1Id = t1.Table1Id, _
               .FieldDescription = t1.FieldDescription, _
               .FieldValue = If(t2gx Is Nothing, String.Empty, t2gx.FieldValue) _
           }
End Function

【问题讨论】:

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


    【解决方案1】:

    试试这些查询,告诉我它们是否适合您。我还没有设置要测试的数据,但它们应该没问题。

    请原谅我混合使用 C# 和 VB.NET。我曾经是一名 VB.NET 开发人员,但在过去的几年中,我主要使用 C# 工作,所以我现在在那里感觉更舒服了。

    这是我为Table1 & Table2 创建的类:

    public class Table1
    {
        public int Table1Id { get; set; }
        public string FieldDescription { get; set; }
        public int OrderByColumn { get; set; }
    }
    public class Table2
    {
        public int Table1Id { get; set; }
        public string FieldValue { get; set; }
        public int Table2WhereColumn1 { get; set; }
        public int Table2WhereColumn2 { get; set; }
    }
    

    现在 C# 中的查询应该是:

    var query =
        from t1 in Table1
        join t2 in Table2 on t1.Table1Id equals t2.Table1Id into _Table2
        from _t2 in _Table2.DefaultIfEmpty()
        where _t2 == null ? true :
            _t2.Table2WhereColumn1 == @someId
            && _t2.Table2WhereColumn2 == @someOtherId
        orderby t1.OrderByColumn
        select new
        {
            t1.Table1Id,
            t1.FieldDescription,
            FieldValue = _t2 == null ? "" : _t2.FieldValue,
        };
    

    并翻译成VB.NET:

    Dim query = _
        From t1 In Table1 _
        Group Join t2 In Table2 On t1.Table1Id Equals t2.Table1Id Into _Table2 = Group _
        From _t2 In _Table2.DefaultIfEmpty() _
        Where If(_t2 Is Nothing, True, _t2.Table2WhereColumn1 = someId AndAlso  _
                                       _t2.Table2WhereColumn2 = someOtherId) _
        Order By t1.OrderByColumn _
        Select New With { _
                .Table1Id = t1.Table1Id, _
                .FieldDescription = t1.FieldDescription, _
                .FieldValue = If(_t2 Is Nothing, "", _t2.FieldValue) _
            }
    

    让我知道它们是否有效。手指交叉。 :-)

    【讨论】:

    • 优秀!奇迹般有效。我不确定我是否理解 Where 子句的工作原理,但它确实有效。
    【解决方案2】:

    就个人而言,如果存在左连接右侧的 where 条件,我通常更喜欢将它们放入连接条件中

    在这种情况下,SQL 如下所示:

    SELECT t1.Table1Id,
           t1.FieldDescription, 
           t2.FieldValue
    FROM Table1 t1 WITH (NOLOCK)
    LEFT JOIN Table2 t2 WITH (NOLOCK) ON t1.Table1Id = t2.Table1Id 
                                      AND t2.Table2WhereColumn1 = @someId
                                      AND t2.Table2WhereColumn2 = @someOtherId
    ORDER BY t1.OrderByColumn
    

    用于此的 LINQ 代码(在 C# 中)如下所示:

    var query =
        from t1 in Table1
        join t2 in Table2 on new{a = t1.Table1Id, b = someId, c = someotherId} 
                             equals new {a = t2.Table1Id b = t2.Table2WhereColumn1, c = Table2WhereColumn2} 
        into _Table2
        from _t2 in _Table2.DefaultIfEmpty()
        orderby t1.OrderByColumn
        select new
        {
            t1.Table1Id,
            t1.FieldDescription,
            FieldValue = _t2 == null ? "" : _t2.FieldValue,
        };
    

    未测试 - 但应该可以工作

    【讨论】:

    • +1 这是我喜欢生成 Linq 右表的方式,其中左外连接上的条件我觉得它读起来更类似于我习惯的 Sql 语法。
    • 语法真的很好。我必须同意更像 SQL 的感觉。
    • 如果在 JOIN 中使用 OR 条件,您如何执行上述操作?
    【解决方案3】:

    我不会把这个答案归功于这个答案,但它很漂亮:LINQ to SQL - Left Outer Join with multiple join conditions

    本质上,在子查询上使用扩展方法 where 子句,但必须在 DefaultIfEmpty() 之前使用它:

    from p in context.Periods
    join f in context.Facts on p.id equals f.periodid into fg
    from fgi in fg.Where(f => f.otherid == 17).DefaultIfEmpty()
    where p.companyid == 100
    select f.value
    

    【讨论】:

    • 简洁大方,完美。
    猜你喜欢
    • 1970-01-01
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 2011-01-30
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    • 2010-11-26
    相关资源
    最近更新 更多