SQL到LINQ有多個join,count和left join



left-join sql-to-linq-conversion (1)

用於將SQL轉換為LINQ查詢理解:

  1. 將子選擇轉換為單獨聲明的變量。
  2. 以LINQ子句順序翻譯每個子句,將monadic和aggregate運算符( DISTINCTTOPMINMAX 等)轉換為應用於整個LINQ查詢的函數。
  3. 使用表別名作為範圍變量。 使用列別名作為匿名類型字段名稱。
  4. 對多個列使用匿名類型( new { ... } )(例如,在 groupby )。
  5. 使用 First().fieldgroupby 聚合範圍變量中獲取非鍵值(例如,與MySQL一樣)。
  6. 不是 AND 所有相等測試的 JOIN 條件必須使用join之外的 where 子句,或者使用cross product( from ... from ...)然後使用 where 。 如果您正在執行 LEFT JOIN ,請在join範圍變量和 DefaultIfEmpty() 調用之間添加lambda Where 子句。
  7. 應將兩個表之間的多個 AND ed相等性測試的 JOIN 條件轉換為匿名對象
  8. LEFT JOIN 是通過使用 join變量 並從 joinvariable .DefaultIfEmpty() 進行另一個來模擬的。
  9. 用條件運算符( ?: COALESCE 替換 COALESCEnull 測試。
  10. IN 轉換為 .Contains()NOT IN ! ... Contains() ,使用文字數組或常量列表的數組變量。
  11. x BETWEEN AND 高轉換 <= x && x <=
  12. CASE 轉換為三元條件運算符 ?:
  13. SELECT * 必須替換為select range_variable或者連接,一個包含所有範圍變量的匿名對象。
  14. SELECT 字段必須替換為 select new { ... } 創建一個包含所有所需字段或表達式的匿名對象。
  15. IIF 轉換為C#三元條件運算符。
  16. 必須使用擴展方法處理正確的 FULL OUTER JOIN
  17. UNION 轉換為 Concat 除非兩個子查詢都是 DISTINCT ,在這種情況下,您可以轉換為 Union 並取消 DISTINCT

將這些規則應用於SQL查詢,您將獲得:

var subrq = from r in Table_R
            group r by r.Id into rg
            select new { Id = rg.Key, cnt = rg.Count() };

var ansq = (from c in Table_C
            join v in Table_V on c.Id equals v.Id
            join r in subrq on c.Id equals r.Id into rj
            from r in rj.DefaultIfEmpty()
            where c.IdUser == "1234"
            group new { c, v, r } by new { c.Id, c.Title, r.cnt } into cvrg
            select new {
                cvrg.Key.Title,
                Nb_V2 = cvrg.Count(),
                Nb_V1 = cvrg.Select(cvr => cvr.v.IdUser).Distinct().Count(),
                Nb_R = (int?)cvrg.Key.cnt
            }).Distinct();

lambda翻譯很棘手,但 LEFT JOIN 轉換為 GroupJoin ... SelectMany 是需要的:

var subr2 = Table_R.GroupBy(r => r.Id).Select(rg => new { Id = rg.Key, cnt = rg.Count() });
var ans2 = Table_C.Where(c => c.IdUser == "1234")
                  .Join(Table_V, c => c.Id, v => v.Id, (c, v) => new { c, v })
                  .GroupJoin(subr, cv => cv.c.Id, r => r.Id, (cv, rj) => new { cv.c, cv.v, rj })
                  .SelectMany(cvrj => cvrj.rj.DefaultIfEmpty(), (cvrj, r) => new { cvrj.c, cvrj.v, r })
                  .GroupBy(cvr => new { cvr.c.Id, cvr.c.Title, cvr.r.cnt })
                  .Select(cvrg => new { cvrg.Key.Title, Nb_V2 = cvrg.Count(), Nb_V1 = cvrg.Select(cvr => cvr.v.IdUser).Distinct().Count(), Nb_R = (int?)cvrg.Key.cnt });

我用多個 JOIN (包括 LEFT JOIN )編寫了這個SQL請求。
它給了我預期的結果

SELECT DISTINCT c.Id, 
       c.Title, 
       COUNT(v.Id) AS 'Nb_V2',
       COUNT(DISTINCT v.IdUser) AS 'Nb_V1',
       r.cnt AS 'Nb_R'
FROM TABLE_C c
JOIN TABLE_V v on c.Id = v.Id
LEFT JOIN ( 
    SELECT Id, COUNT(*)  AS cnt 
    FROM TABLE_R 
    GROUP BY Id
) r ON c.Id = r.Id
WHERE c.IdUser = '1234'
GROUP BY c.Id, c.Title, r.cnt

但是,'Id喜歡Linq等同於此請求,將它放在我的應用程序的數據訪問層。

我嘗試過類似的東西:

var qResult = from c in dbContext.TABLE_C
              join v in dbContext.TABLE_V on c.IdC equals v.IdC
              join r in dbContext.TABLE_R on v.IdC equals r.IdC into temp
              from x in temp.DefaultIfEmpty()
              group x by new { c.IdC, c.Title /*miss something ?*/} into grouped
              select new
              {
                  IdC = grouped.Key.IdC,          --good result
                  Title = grouped.Key.Title,      --good result
                  NbR = grouped.Distinct().Count(t => t.IdC > 0), --good, but "t.Id > 0" seems weird
                  Count = --I'm lost. No idea how to get my COUNT(...) properties (Nb_V1 and Nb_V2)
              };

我試圖適應 這個問題, 但我無法弄清楚。 我在分組子請求中丟失了 Count
誰能解釋我哪裡錯了?

專業提示:如果有人可以使用lambda表達式編寫等效內容,則可獲得獎勵積分





sql-to-linq-conversion