C# LINQ到SQL:多列上的多个联接。这可能吗?

C# LINQ到SQL:多列上的多个联接。这可能吗?,c#,linq-to-sql,left-join,multiple-columns,C#,Linq To Sql,Left Join,Multiple Columns,给定: 名为table_1的表包含以下列: ID ColumnA ColumnB ColumnC 我有一个SQL查询,其中表_1基于列a,列b,列c自身连接两次。查询可能如下所示: 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.C

给定:

名为
table_1
的表包含以下列:

  • ID
  • ColumnA
  • ColumnB
  • ColumnC
我有一个SQL查询,其中
表_1
基于
列a
列b
列c
自身连接两次。查询可能如下所示:

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 :(
var查询=
从myTABLE1List//列表中的t1开始
在MyTable1列表中加入t2
在t1.ColumnA上等于t2.ColumnA
&&t1.ColumnB等于t2.ColumnA
// ... 在这一点上,intellisense使它变得非常明显
//我做错了什么事:(

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

在LINQ到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 }
    ...
var查询=
从myTABLE1List//列表中的t1开始
在MyTable1列表中加入t2
在新的{t1.ColumnA,t1.ColumnB}上等于新的{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 }
    ...
var查询=
从myTABLE1List//列表中的t1开始
在MyTable1列表中加入t2
在新的{A=t1.ColumnA,B=t1.ColumnB}上等于新的{A=t2.ColumnA,B=t2.ColumnB}
在MyTable1列表中加入t3
在新的{A=t2.ColumnA,B=t2.ColumnB}上等于新的{A=t3.ColumnA,B=t3.ColumnB}
...

在LINQ2SQL中,使用内部联接时很少需要显式联接

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

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

将生成查询

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
在我看来,这更具可读性,可以让您专注于特殊条件,而不是连接的实际机制

编辑

当然,这仅适用于您想加入我们的数据库模型的情况。如果您想加入“模型外”,您需要求助于手动加入,如from

标题中所述。作者是一个查找两件事一次加入项目结果并继续链接的过程

        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;
        }
你也可以使用:

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)个连接

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

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

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}

A和B别名必须与“equal new”筛选器中e表和t表中的Hrco和位置代码-Hrco和位置代码组合对齐。这将节省您的时间,因为我一直收到“Not in scope on The left side”编译错误,因为我认为该筛选器是筛选器的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>();
从表1e中选择*
加入表2
e、 Hrco=t.Hrco和e.PositionCode=t.PositionCode
注意列与标签A和B的关联。As equal和Bs equal过滤器。
IList list=await(来自_dbContext.table1中的e
在_dbContext.table2中加入t
关于新的{A=e.Hrco,B=e.PositionCode}
等于新的{A=t.Hrco,B=t.PositionCode}
其中e.XMan==员工编号
选择新建MyView
{ 
雇员=雇员,
LastName=e.LastName,
FirstName=e.FirstName,
Title=t.JobTitle
).ToListAsync();

这对于两个联接非常有效。我需要它来处理三个联接。抱歉,第二个代码块有点误导。如果您在类型推断方面遇到编译器错误,请检查两件事:(1)类型是否相同,以及(2)列名是否相同。名称部分是一个gotcha。即使所有列都是varchars
join T2 in db.tbl2 on new{T1.firstName,T1.secondName}等于new{T2.colFirst,T2.colSecond}
,此示例也不会编译。但是,如果将其更改为此,它将编译为
join T2 in db.tbl2 on new{N1=T1.firstName,N2=T1.secondName}等于新的{N1=T2.colFirst,N2=T2.colSecond}
命名问题可以通过从myTABLE1List中的T1在新的{colA=T1.ColumnA,colB=T1.ColumnB}上加入myTABLE1List中的T2来解决请允许我编辑该示例,因为它需要分配到匿名属性这里有些东西是错误的..使用LINQ。我可以在多个表上进行连接,我可以在多个字段上进行连接…但是,我不能同时对这两个表进行连接,如示例所示。因此,假设您在1个字段上有一个连接..然后有第二个连接。如果您更改第一个连接join(或两者)只使用new{x.field}等于new{y.field}有一个编译器错误。从功能上讲,您没有更改任何内容。使用.Net 4.6.1。这不一样-问题是关于基于每一列中的多个列连接表,而不是基于每一列中的一个列连接多个表。是的,我看不出这个答案在这里有什么作用。啊哈!!这很有效!关键的区别是,您需要做“ColA=”部分,以便在另一个领域加入相同的领域。多年来我都没有这样做,
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>();