[LINQ]Join&GroupJoin 用法

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。

 

 

一天一分享,身體好健康。

該追究的不是過去的原因,而是現在的目的。