用 Linq to SQL 完成Left join-DefaultIfEmpty

用 Linq to SQL 完成Left join-DefaultIfEmpty

一個資料庫要是正規化做得好,往往查一個資料都要join來join去的。

這幾個月因為都一直在用Linq to SQL,因此很多繁複的T-SQL指令都比較少在用了

只要關聯有拉好,用點的就可以點到關聯的table,省去很多麻煩。

但最近為了一個以前輕鬆可以做到的left join可是燒了一下頭。

因為用點的,只點的到有相關聯的資料,要是子table裡沒有父table的某筆PK

那該筆父table的資料就會撈不到。

上網查了一下,查到有個方法可以解決這個問題 Enumerable.DefaultIfEmpty 方法

不過大部分的寫法 都是用Linq Expression方式寫的(範例LEFT JOINS and DefaultIfEmpty Operator in LINQ)。

但我比較習慣用lambda寫法,所以就紀錄一下改寫成lambda的樣子

首先先來看table,簡單的關聯

image

裡面建的假資料,我故意把某一個類別(筆電)做成沒有關聯資料。

image

接著開始用拉一個Linq to SQL,然後寫Code

image

我個人覺得SelectMany非常好用,因為可再傳入一個資料集,並且可利用原資料集對第二個資料集做篩選。

寫完之後,利用SQL Server Profiler來看看他組出什麼樣的T-SQL語法

image

看起來非常好,就是我要的。再隨便補上一點Code,看實際撈出資料的結果


public ActionResult Index()
{
    MyDataContext db = new MyDataContext();

    var 類別=db.類別;

    var 產品資訊 = 類別.SelectMany(p => p.產品.DefaultIfEmpty()
                           , (c, d) => new { 類別名稱=c.名稱,產品名稱=d.產品名稱});


    StringBuilder sb = new StringBuilder();

    sb.Append("<table style='border:1px solid red'>");

    foreach(var p in 產品資訊.OrderBy(p=>p.類別名稱)){
        sb.Append("<tr><td>" + p.類別名稱 + "</td><td>" + p.產品名稱 + "</td></tr>");
    }
    sb.Append("</table>");

    return Content(sb.ToString());
}

image

這樣就完成啦。

補充一下:

要是沒有加DefaultIfEmpty()的話


var 產品資訊 = 類別.SelectMany(p => p.產品
                              , (c, d) => new { 類別名稱=c.名稱,產品名稱=d.產品名稱});

,產出來的T-SQL語法就變成下面這樣

image

結果當然就是,沒有的那個類別不會出現了。

image