在*上看到关于这个问题的讨论,打算记录下来。
关于全连接(Full Outer Join),Linq并不支持,所以就需要使用其它方法来实现,就像不支持全连接的数据库一样,先使用内连接找出公共的部分,然后分别找出左连接和右连接的部分,把这三部分的结果UNION一下,即可得到全连接的效果。
看问题:
ID FirstName -- --------- 1 John 2 Sue ID LastName -- -------- 1 Doe 3 Smith
显示下面的结果:
ID FirstName LastName -- --------- -------- 1 John Doe 2 Sue 3 Smith
实现方法一:
先找出左连接的结果,再找出右连接的结果,然后把这两个结果UNION即可,UNION时会自动把重复的数据过滤掉。
var firstNames = new[] { new { ID = 1, Name = "John" }, new { ID = 2, Name = "Sue" }, }; var lastNames = new[] { new { ID = 1, Name = "Doe" }, new { ID = 3, Name = "Smith" }, }; var leftOuterJoin = from first in firstNames join last in lastNames on first.ID equals last.ID into temp from last in temp.DefaultIfEmpty(new { first.ID, Name = default(string) }) select new { first.ID, FirstName = first.Name, LastName = last.Name, }; var rightOuterJoin = from last in lastNames join first in firstNames on last.ID equals first.ID into temp from first in temp.DefaultIfEmpty(new { last.ID, Name = default(string) }) select new { last.ID, FirstName = first.Name, LastName = last.Name, }; var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin);
方法二:
得到左连接的数据,再从右连接的数据中把左连接的数据排除掉,两者的数据Concat一下即可
var firstNames = new[] { new { ID = 1, Name = "John" }, new { ID = 2, Name = "Sue" }, }; var lastNames = new[] { new { ID = 1, Name = "Doe" }, new { ID = 3, Name = "Smith" }, }; var leftData = (from first in firstNames join last in lastNames on first.ID equals last.ID into temp from last in temp.DefaultIfEmpty(new { first.ID, Name = default(string) }) select new { first.ID, FirstName = first.Name, LastName = last.Name, }); var rightRemainingData = (from r in lastNames where !(from a in leftData select a.ID).Contains(r.ID) select new { r.ID, FirstName = default(string), LastName = r.Name }); var fullOuterjoinData = leftData.Concat(rightRemainingData);
以上两种方法,其实是同一种方式来实现全连接的,只是第二次拿出的数据有所不同。
以上,希望对大家有所帮助。