【问题标题】:LINQ to SQL: Multiple joins ON multiple Columns. Is this possible?LINQ to SQL:多个列上的多个连接。这可能吗?
【发布时间】:2011-07-15 12:43:56
【问题描述】:

鉴于:

一个名为 TABLE_1 的表,包含以下列:

  • ID
  • ColumnA
  • ColumnB
  • ColumnC

我有一个 SQL 查询,其中TABLE_1 根据ColumnAColumnBColumnC 两次连接自身。查询可能如下所示:

Select t1.ID, t2.ID, t3.ID
  From TABLE_1 t1
  Left Join TABLE_1 t2 On
       t1.ColumnA = t2.ColumnA
   And t1.ColumnB = t2.ColumnB
   And t1.ColumnC = t2.ColumnC
  Left Join TABLE_1 t3 On
       t2.ColumnA = t3.ColumnA
   And t2.ColumnB = t3.ColumnB
   And t2.ColumnC = t3.ColumnC
... and query continues on etc.

问题:

我需要在 LINQ 中重写该查询。我试过尝试一下:

var query =
    from t1 in myTABLE1List // List<TABLE_1>
    join t2 in myTABLE1List
      on t1.ColumnA equals t2.ColumnA
      && t1.ColumnB equals t2.ColumnA
    // ... and at this point intellisense is making it very obvious
    // I am doing something wrong :(

如何在 LINQ 中编写查询?我做错了什么?

【问题讨论】:

    标签: c# linq-to-sql left-join multiple-columns


    【解决方案1】:

    在 Linq to SQL 中连接多个列有点不同。

    var query =
        from t1 in myTABLE1List // List<TABLE_1>
        join t2 in myTABLE1List
          on new { t1.ColumnA, t1.ColumnB } equals new { t2.ColumnA, t2.ColumnB }
        ...
    

    您必须利用匿名类型并为要比较的多个列组成一个类型。

    一开始这似乎令人困惑,但是一旦您熟悉了 SQL 由表达式组成的方式,它就会变得更有意义,在幕后,这将生成您正在寻找的连接类型。

    编辑添加基于评论的第二次加入示例。

    var query =
        from t1 in myTABLE1List // List<TABLE_1>
        join t2 in myTABLE1List
          on new { A = t1.ColumnA, B = t1.ColumnB } equals new { A = t2.ColumnA, B = t2.ColumnB }
        join t3 in myTABLE1List
          on new { A = t2.ColumnA, B =  t2.ColumnB } equals new { A = t3.ColumnA, B = t3.ColumnB }
        ...
    

    【讨论】:

    • 这适用于两个连接。我需要它与三个连接一起工作。抱歉,第二个代码块有点误导。
    • 如果您收到关于类型推断的编译器错误,请检查两件事,(1) 类型是否相同,(2) 列名是否相同。名称部分是一个陷阱。即使所有列都是 varchars join T2 in db.tbl2 on new { T1.firstName, T1.secondName } equals new { T2.colFirst, T2.colSecond },此示例也不会编译。如果你把它改成这个,它会编译,join T2 in db.tbl2 on new { N1 = T1.firstName, N2 = T1.secondName } equals new { N1 = T2.colFirst, N2 = T2.colSecond }
    • 命名问题可以通过 from t1 in myTABLE1List join t2 in myTABLE1List on new { colA=t1.ColumnA, colB=t1.ColumnB } equals new { colA=t2.ColumnA, colBBt2.ColumnB }
    • 请允许我编辑示例,因为它需要分配给匿名属性
    • 这里出了点问题.. 使用 LINQ。我可以加入多个表,我可以加入多个字段......但是,我不能同时做这两个,如示例所示here。所以说你只是在 1 个字段上加入了......并且你有一个跟随它的第二个加入。如果您将第一个连接(或两者)更改为仅使用 new { x.field } equals new { y.field } ,则会出现编译器错误。从功能上讲,你没有改变任何东西。使用 .Net 4.6.1。
    【解决方案2】:

    你也可以使用:

    var query =
        from t1 in myTABLE1List 
        join t2 in myTABLE1List
          on new { ColA=t1.ColumnA, ColB=t1.ColumnB } equals new { ColA=t2.ColumnA, ColB=t2.ColumnB }
        join t3 in myTABLE1List
          on new {ColC=t2.ColumnA, ColD=t2.ColumnB } equals new { ColC=t3.ColumnA, ColD=t3.ColumnB }
    

    【讨论】:

    • 啊啊啊!!这行得通!关键的区别在于,您需要执行“ColA =”部分,以便在另一个加入中它是相同的字段。多年来我没有这样做,但也只需要在多个字段上加入 1 个。但是现在我需要更多,而且只有在我为这个例子中的字段分配一个变量名时它才有效。
    【解决方案3】:

    在 LINQ2SQL 中,使用内连接时很少需要显式连接。

    如果您的数据库中有正确的外键关系,您将在 LINQ 设计器中自动获得一个关系(如果没有,您可以在设计器中手动创建一个关系,尽管您的数据库中应该有正确的关系)

    然后您可以使用“点符号”访问相关表

    var q = from child in context.Childs
            where child.Parent.col2 == 4
            select new
            {
                childCol1 = child.col1,
                parentCol1 = child.Parent.col1,
            };
    

    将生成查询

    SELECT [t0].[col1] AS [childCol1], [t1].[col1] AS [parentCol1]
    FROM [dbo].[Child] AS [t0]
    INNER JOIN [dbo].[Parent] AS [t1] ON ([t1].[col1] = [t0].[col1]) AND ([t1].[col2] = [t0].[col2])
    WHERE [t1].[col2] = @p0
    -- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [4]
    -- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1
    

    在我看来,这更具可读性,可以让您专注于您的特殊条件,而不是连接的实际机制。

    编辑
    这当然只适用于您想加入符合我们的数据库模型的情况。如果您想在“模型外”加入,则需要像 answer 中的 Quintin Robinson 中的手动加入

    【讨论】:

      【解决方案4】:

      Title_Authors 是一次查找两件事加入项目结果并继续链接

              DataClasses1DataContext db = new DataClasses1DataContext();
              var queryresults = from a in db.Authors                                          
                          join ba in db.Title_Authors                           
                          on a.Au_ID equals ba.Au_ID into idAuthor
                          from c in idAuthor
                          join t in db.Titles  
                          on c.ISBN equals t.ISBN 
                          select new { Author = a.Author1,Title= t.Title1 };
      
              foreach (var item in queryresults)
              {
                  MessageBox.Show(item.Author);
                  MessageBox.Show(item.Title);
                  return;
              }
      

      【讨论】:

        【解决方案5】:

        我想再举一个使用多 (3) 个连接的例子。

         DataClasses1DataContext ctx = new DataClasses1DataContext();
        
                var Owners = ctx.OwnerMasters;
                var Category = ctx.CategoryMasters;
                var Status = ctx.StatusMasters;
                var Tasks = ctx.TaskMasters;
        
                var xyz = from t in Tasks
                          join c in Category
                          on t.TaskCategory equals c.CategoryID
                          join s in Status
                          on t.TaskStatus equals s.StatusID
                          join o in Owners
                          on t.TaskOwner equals o.OwnerID
                          select new
                          {
                              t.TaskID,
                              t.TaskShortDescription,
                              c.CategoryName,
                              s.StatusName,
                              o.OwnerName
                          };
        

        【讨论】:

        • 不是一回事 - 问题是关于基于每个列中的多个列连接表,而不是基于每个列中的单个列连接多个表。
        • 是的,我看不出这个答案在这里做了什么。
        【解决方案6】:

        如果两个表中的列数不相同,也可以加入,并且可以将静态值映射到表列

        from t1 in Table1 
        join t2 in Table2 
        on new {X = t1.Column1, Y = 0 } on new {X = t2.Column1, Y = t2.Column2 }
        select new {t1, t2}
        

        【讨论】:

          【解决方案7】:

          您可以使用 LINQ 方法语法来连接多个列。这是一个例子,

          var query = mTABLE_1.Join( // mTABLE_1 is a List<TABLE_1>
                          mTABLE_1, 
                          t1 => new
                          {
                              ColA = t1.ColumnA,
                              ColB = t1.ColumnB,
                              ColC = t1.ColumnC
                          },
                          t2 => new
                          {
                              ColA = t2.ColumnA,
                              ColB = t2.ColumnB,
                              ColC = t2.ColumnC
                          },
                          (t1, t2) => new { t1, t2 }).Join(
                          mTABLE_1,
                          t1t2 => new
                          {
                              ColA = t1t2.t2.ColumnA,
                              ColB = t1t2.t2.ColumnB,
                              ColC = t1t2.t2.ColumnC
                          },
                          t3 => new
                          {
                              ColA = t3.ColumnA,
                              ColB = t3.ColumnB,
                              ColC = t3.ColumnC
                          },
                          (t1t2, t3) => new
                          {
                              t1 = t1t2.t1,
                              t2 = t1t2.t2,
                              t3 = t3
                          });
          

          注意:编译器在编译时将查询语法转换为方法语法。

          【讨论】:

            【解决方案8】:

            A 和 B 别名必须与 e 表和 t 表中的 Hrco 和 Position 代码对齐 - “equal new”过滤器中的 Hrco 和 Position 代码组合。这将节省您的时间,因为我一直收到“不在左侧范围内”的编译错误,因为我认为过滤器是 e.Hrco,t.Hrco 与过滤器配对。

            select * from table1 e
               join table2 t on
                  e.Hrco=t.Hrco and e.PositionCode=t.PositionCode
            
               Notice the association of the columns to the labels A and B. The As equal and the Bs equal filter.
            
               IList<MyView> list = await (from e in _dbContext.table1
                                                          join t in _dbContext.table2
                                                          on new { A= e.Hrco, B= e.PositionCode }
                                                          equals new {A= t.Hrco,B=t.PositionCode }
                                                          where e.XMan == employeeNumber
            
                                                          select new MyView
                                                                              { 
                                                                                    
                     Employee=e.Employee,
                     LastName=e.LastName,
                     FirstName=e.FirstName,
                     Title=t.JobTitle
                     ).ToListAsync<MyView>();
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-05-06
              • 2010-09-21
              • 1970-01-01
              • 2010-09-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-11-13
              相关资源
              最近更新 更多