LINQ to SQL:多个列上的多个连接。这可能吗?
Posted
技术标签:
【中文标题】LINQ to SQL:多个列上的多个连接。这可能吗?【英文标题】:LINQ to SQL: Multiple joins ON multiple Columns. Is this possible? 【发布时间】:2011-07-15 12:43:56 【问题描述】:鉴于:
一个名为 TABLE_1
的表,包含以下列:
ID
ColumnA
ColumnB
ColumnC
我有一个 SQL 查询,其中TABLE_1
根据ColumnA
、ColumnB
、ColumnC
两次连接自身。查询可能如下所示:
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 中编写查询?我做错了什么?
【问题讨论】:
【参考方案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) 列名是否相同。名称部分是一个陷阱。即使所有列都是 varcharsjoin 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>();
【讨论】:
以上是关于LINQ to SQL:多个列上的多个连接。这可能吗?的主要内容,如果未能解决你的问题,请参考以下文章
Linq to SQL 使用 Lambda 语法进行左外连接并在 2 列上连接(复合连接键)