Join&GroupJoin
Join & GropuJoin
寫SQL常常會用到LEFT JOIN跟INNER JOIN,平常SQL寫得很習慣了,結果換到Entity Framework來後,覺得寫法比較特殊,而且網路上也很少分享擴充方法的寫法,所以在這邊先紀錄下來。
以這個例子來說,一個Student可以選擇多個Course,是一個一對多的關係。
Inner Join
這是我想達成的SQL
SELECT * FROM Student s
INNER JOIN Course c ON (s.Id = c.SutdentId)
要使用Entity Framework達成Inner Join 其實還蠻簡單的,我們先來看Join的宣告
看完宣告後,程式這樣寫
LinqDemoEntities db = new LinqDemoEntities();
var data = db.Student
.Join(
db.Course, //跟Course LEFT JOIN
std => std.Id, //Student 對應Course 的欄位值為 Id
crs => crs.SutdentId, //Course 對應Student 的欄位值為SutdentId
(std, crs) => new {
std.Id, //輸出Student Id
std.Name, //輸出Student Name
crs.CourseName //輸出Course CourseName
}
);
產生的SQL
SELECT [Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent2].[CourseName] AS [CourseName]
FROM [dbo].[Student] AS [Extent1]
INNER JOIN [dbo].[Course] AS [Extent2] ON [Extent1].[Id] = [Extent2].[SutdentId]
達成目的
Left Join
要達成Left Join就比較複雜一點點,而且要用到兩個擴充方法才能達成,一個是GroupJoin另一個是SelectMany。
我們先來看GroupJoin的宣告
GroupJoin跟Join最大的差別就是,最後一個傳入參數的Func是傳入 Student 跟 IEnumerable<Course>,這將是我們達成Left Join的關鍵之一。
我們先來看單純用GroupJoin會輸出什麼結果
LinqDemoEntities db = new LinqDemoEntities();
var data = db.Student
.GroupJoin(
db.Course, // 要Join的Table,這裡指Course
std => std.Id, // Student對應Course的欄位是Id
crs => crs.SutdentId, // Course對應Student的欄位是SutdentId
(std, crs) => new
{
std.Id, // 輸出Student Id
std.Name, // 輸出Student Name
crs = crs // 輸出IEnumerable<Course>
}
)
得到結果的data是一個匿名型別,而長相可以說是這個樣子
public class Anonym
{
public int Id { get; set; }
public string Name { get; set; }
public List<Course> Crs { get; set; }
}
以上這個並不是我們要的結果。
我們希望的結果是能跟Join一樣,能夠是以下的樣子。
public class Anonym
{
public int Id { get; set; }
public string Name { get; set; }
public string CourseName { get; set; }
}
所以這時候就要使用SelectMany,來達成要輸出的結果。
(如果這邊不懂SelectMany在做什麼的,請先點選[LINQ]SelectMany用法,清楚知道SelectMany的用法後,再來看這段會比較容易理解)
LinqDemoEntities db = new LinqDemoEntities();
var data = db.Student
.GroupJoin(
db.Course,
std => std.Id,
crs => crs.SutdentId,
(std, crs) => new { std.Id, std.Name, crs = crs }
)
.SelectMany(
x => x.crs.DefaultIfEmpty(), //要使用DefaultIfEmpty,才能轉換成Left Join
(std, crs) => new
{
std.Id, //輸出Student Id
std.Name, //輸出Student Name
crs.CourseName //輸出Course CourseName
}
);
如果沒有使用DefaultIfEmpty,則Entity Framework會轉換成Inner Join,這並不是我們要的結果,所以如果要產生Left Join要記得加上去。
產生的SQL
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent2].[CourseName] AS [CourseName]
FROM [dbo].[Student] AS [Extent1]
LEFT OUTER JOIN [dbo].[Course] AS [Extent2] ON [Extent1].[Id] = [Extent2].[SutdentId]
達成目的
提示:
如果有多個欄位要對應的話,對應欄位那兩個參數,可用匿名型別的方式對應
小結:
Inner Join還蠻簡單的,只要看懂Join的宣告就知道怎麼寫。 而Left Join比較難第一次就看懂,要先知道GroupJoin產生的結果,再用SelectMany補助,才能達到Left Join。
一天一分享,身體好健康。
該追究的不是過去的原因,而是現在的目的。