zoukankan      html  css  js  c++  java
  • 关于Linq翻译Inner join ,Left join (本文为转载)

    我們先來一段最基本的 LINQ to SQL 使用類似 T-SQL 的 INNER JOIN 資料查詢語法:

    from c in Categories
    from o in c.Products
    select new { c.CategoryName, o.ProductID, o.ProductName }

    我們可以從上述 LINQ 語法上就知道有兩個資料來源(因為有兩個 from 子句),而第二個 from 使用的是第一個 from 資料來源的關連屬性,因此產生 JOIN 需求,這段 LINQ 語法所產生的 T-SQL 語句如下:

    SELECT [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName]
    FROM [Categories] AS [t0], [Products] AS [t1]
    WHERE [t1].[CategoryID] = [t0].[CategoryID]

    接著我們來看看另一個 INNER JOIN 的資料查詢語法,我們使用語意更為明確的 join 子句:

    from c in Categories
    join o in Products on c.CategoryID equals o.CategoryID 
    select new { c.CategoryName, o.ProductID, o.ProductName }

    我們可以從上述 LINQ 語法上知道有一個 Categories 資料來源,並且 join 另一個 Products 資料來源,當中用這個兩個實體的其中一個 CategoryID 屬性進行 join 動作,這是一個非常明確的 join 語法,其語法與 T-SQL 的 join 語法非常相近,這段 LINQ 語法所產生的 T-SQL 語句如下:

    SELECT [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName]
    FROM [Categories] AS [t0]
    INNER JOIN [Products] AS [t1] ON ([t0].[CategoryID]) = [t1].[CategoryID]

    這兩段 LINQ 語法所執行的結果資料一模一樣,不過產生的 T-SQL 不一樣,所以透過 LINQ to SQL 會自動將設定的 LINQ 語法產生出合適的 T-SQL 語法。不過,我們都知道資料庫查詢的 SQL 語法有很多調校的技巧,透過 LINQ to SQL 之後自然會變的不容易調校,所以針對某些 LINQ 語法還是有可能產生效能不彰的狀況需要自行處理。

    舉個例子來說,以下 LINQ 語法除了 join 外還在 select 的地方有隱含的使用了另一個 JOIN 條件:

    from c in Categories
    join o in Products on c.CategoryID equals o.CategoryID 
    select new { o.Category.CategoryName ,o.ProductID, o.ProductName }

    因此會產生出一個詭異且無效率的 T-SQL 語法如下,同時有 INNER JOINLEFT OUTER JOIN 的狀況:

    SELECT [t2].[CategoryName], [t0].[ProductID], [t0].[ProductName]
    FROM [Products] AS [t0]
    INNER JOIN [Categories] AS [t1] ON [t0].[CategoryID] = ([t1].[CategoryID])
    LEFT OUTER JOIN [Categories] AS [t2] ON [t2].[CategoryID] = [t0].[CategoryID]

    這時我們修正 LINQ 語法如下:

    from c in Categories
    join o in Products on c.CategoryID equals o.CategoryID 
    select new { c.CategoryName, o.ProductID, o.ProductName }

    這時就會產生預期的 T-SQL 語法:

    SELECT [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName]
    FROM [Categories] AS [t0]
    INNER JOIN [Products] AS [t1] ON ([t0].[CategoryID]) = [t1].[CategoryID]

    雖然 LINQ 出現的目的就是希望你改用「物件」與「實體」的角度來思考資料的查詢方式,不過如果你能瞭解從 LINQ 轉換到 T-SQL 的過程將有助於你寫出更有效率的 LINQ 查詢語法。

    瞭解 INNER JOIN 之後,我們再來看一個 T-SQL 中常見的 LEFT JOIN 語法的 LINQ 要如何撰寫:

    from o in Products
    select new { o.Category.CategoryName, o.ProductID, o.ProductName }

    這段 LINQ 語法我們只取出一個 Products 資料來源,但是在 select 子句卻額外取得 Category 關連實體的資料,這個關連是「多對一」的關連,所以一個 Product 實體只會取得一個 Category 實體,所以轉換 T-SQL 之後你會發現 LEFT JOIN 的左邊就是 Products,而右邊就變成 Categories,其所產生的 T-SQL 語句如下:

    SELECT [t1].[CategoryName], [t0].[ProductID], [t0].[ProductName]
    FROM [Products] AS [t0]
    LEFT OUTER JOIN [Categories] AS [t1] ON [t1].[CategoryID] = [t0].[CategoryID]

    雖然你看到的是一個 LEFT JOIN 語法,不過這並不是我們常見的那種 JOIN 狀況,比較複雜的狀況是當我們左側的實體為 Categories 以及右側的實體為 Products 的狀況,這是「一對多」的關連,複雜度相對提高一些。

    由於 INNER JOIN交集(AND) 的概念,當兩個 JOIN 的實體都有資料時才有資料。而 LEFT JOIN 的概念卻是「左邊的資料全部都要有,即便右邊沒有資料也要以 null 代替」,因此我們的 LINQ to SQL 語法如下就要特別注意資料來源出現的順序性:

    我們先重寫文章稍早出現的過的 INNER JOIN 語法如下:

    from c in Categories
    join o in Products on c.CategoryID equals o.CategoryID 
    select new { c.CategoryName, o.ProductName }

    如果要改成 LEFT JOIN 語法,則必須修改成以下 LINQ 語法:

    from c in Categories
    join o in Products on c.CategoryID equals o.CategoryID into ps
    from o in ps.DefaultIfEmpty()
    select new { c.CategoryName, o.ProductName }

    因為撰在 LINQ 撰寫 LEFT JOIN 時的觀念與 T-SQL 不太一樣,要用「物件」的角度比較能理解其語法所代表的意義,所以上述的語法可以這樣解釋:

    取出 Categories 資料並放入 c 變數,接著再與 Products 做 JOIN 並將 JOIN 後的結果放入 ps 變數(注意:並非第二行的 o 變數),這時再宣告一個資料來源 o 其資料來自於「修改過的 ps 變數」,且修改的方式為 ps.DefaultIfEmpty(),意即代表若 ps ( 也就是 Products 經過 join 篩選後的資料 ) 無任何資料時,還是回傳一筆 Default 的資料(也就是預設的 null 資料)。

    這一段 LINQ 所產生的 T-SQL 如下:

    SELECT [t0].[CategoryName], [t1].[ProductName] AS [ProductName]
    FROM [Categories] AS [t0]
    LEFT OUTER JOIN [Products] AS [t1] ON ([t0].[CategoryID]) = [t1].[CategoryID]

    因此當你需要撰寫「多對一」關連情況下正確的使用 LINQ 查詢語法做 LEFT JOIN 就必須這樣來撰寫!

    不過有一點必須注意,那就是當 o 取得的物件為 null 時,雖然 select 子句中的 o.ProductName 不會引發例外,而且會回傳 null,但是若你在 select 子句中設定 o.ProductID 的話,那就會引發例外,因為 null 並無法正確轉型成 Int32 型別,錯誤訊息是:InvalidOperationException - 無法將 Null 值指派給型別 System.Int32 的成員,該型別不可為 Null 值。

         文章来源:http://blog.miniasp.com/post/2010/10/14/LINQ-to-SQL-Query-Tips-INNER-JOIN-and-LEFT-JOIN.aspx

  • 相关阅读:
    防删没什么意思啊,直接写废你~
    绝大多数情况下,没有解决不了的问题,只有因为平时缺少练习而惧怕问题的复杂度,畏惧的心理让我们选择避让,采取并不那么好的方案去解决问题
    Java 模拟面试题
    Crossthread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on
    一步步从数据库备份恢复SharePoint Portal Server 2003
    【转】理解 JavaScript 闭包
    Just For Fun
    The database schema is too old to perform this operation in this SharePoint cluster. Please upgrade the database and...
    Hello World!
    使用filter筛选刚体碰撞
  • 原文地址:https://www.cnblogs.com/yingger/p/3407623.html
Copyright © 2011-2022 走看看