LINQ to SQL:在多个列上进行多个联接。这可能吗?


131

鉴于:

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中编写查询?我究竟做错了什么?

Answers:


242

在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 }
    ...

4
这非常适合两次连接。我需要它与三个联接一起工作。抱歉,第二个代码块有些误导。
2011年

46
如果您收到有关类型推断的编译器错误,请检查两件事:(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 }
2013年

4
可以通过从myTABLE1List中的t1加入new {colA = t1.ColumnA,colB = t1.ColumnB}上的myTABLE1List中的t2等于new {colA = t2.ColumnA,colBBt2.ColumnB}消除命名问题
Baqer Naqvi

1
请允许我编辑该示例,因为它需要分配给匿名属性
AceMark

1
LINQ在这里有些问题。我可以在多个表上进行联接,也可以在多个字段上进行联接...但是,如此处示例所示,我不能对两个表都进行联接。因此,假设您仅在1个字段上有一个联接。然后紧随其后的是第二个联接。如果您将第一个联接(或两者)更改为仅使用new {x.field}等于new {y.field},则会出现编译器错误。从功能上讲,您没有进行任何更改。使用.Net 4.6.1。
user2415376

12

在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

我认为这更具可读性,可让您专注于特殊条件,而不是联接的实际机制。

编辑
当然,这仅在您希望加入我们的数据库模型行时适用。如果你想加入“模型之外”你需要求助于手动加入作为答案昆廷·罗宾逊


11

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;
        }

10

U也可以使用:

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 }

3
啊!这可行!关键的区别在于,您需要执行“ ColA =”部分,以便在另一个联接中使用相同的字段。多年以来,我一直没有这样做,但只需要在多个字段上进行1次联接即可。但是现在我需要更多,并且只有在像本例中那样为字段分配变量名称时,它才起作用。
user2415376

3

我想举一个使用多个(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
                  };

9
不一样的是-问题是关于基于每个表中的多个列联接表,而不是基于每个表中的单个列联接多个表。
2015年

1

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

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}

-6

我认为,这是联接具有多个字段的两个表的最简单方法:

from a in Table1 join b in Table2    
       on (a.Field1.ToString() + "&" + a.Field2.ToString())     
       equals  (b.Field1.ToString() + "&" + b.Field2.ToString())  
     select a

在SQL中,这样做比分别连接每个列要慢得多(尽管如果数据集不大,这样做仍然会非常快)。大概linq会生成明显的SQL,因此如果使用此解决方案,请牢记性能。
EGP 2013年

-10

您可以这样编写查询。

var query = from t1 in myTABLE1List // List<TABLE_1>
            join t2 in myTABLE1List
               on t1.ColumnA equals t2.ColumnA
               and t1.ColumnB equals t2.ColumnA

如果要将列与多个列进行比较。


1
@ user658720欢迎使用StackOverFlow :)。我建议您格式化代码,以使其更易于阅读。您可以选择文本,然后单击编辑器上的代码按钮。
阿罗纳2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.