SQL إلى LINQ مع صلة متعددة ، العد والانضمام الأيسر



join left-join (1)

كتبت طلب SQL هذا مع عدة JOIN (بما في ذلك LEFT JOIN ).
هذا يعطيني النتيجة المتوقعة .

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

ومع ذلك ، 'معرف مثل 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)
              };

لقد حاولت تكييف هذا السؤال SO ولكن لا يمكنني معرفة ذلك. لقد فقدت مع Count داخل الطلب الفرعي.
هل يستطيع أحد أن يشرح لي أين أكون مخطئًا؟

نصيحة للمحترفين: نقطة المكافأة إذا كان شخص ما يمكنه كتابة ما يعادلها باستخدام تعبير lambda


لترجمة SQL إلى فهم استعلام LINQ:

  1. ترجمة المتغيرات الفرعية كمتغيرات معلن عنها بشكل منفصل.
  2. قم بترجمة كل جملة بترتيب جملة LINQ ، وترجمة العوامل الأحادية والتجميعية ( DISTINCT ، TOP ، MIN ، MAX ، إلخ) إلى وظائف مطبقة على استعلام LINQ بأكمله.
  3. استخدم الأسماء المستعارة في الجدول كمتغيرات نطاق. استخدم الأسماء المستعارة للأعمدة كأسماء حقول نوع مجهولة.
  4. استخدم أنواع مجهولة المصدر ( new { ... } ) جديدة لأعمدة متعددة (على سبيل المثال في groupby ).
  5. استخدم First().field للحصول على قيم غير أساسية من متغير مجموعة التجميع groupby (مثل مع MySQL).
  6. يجب التعامل مع شروط JOIN التي ليست كلها اختبارات للمساواة مع AND where يتم استخدام جمل خارج الصلة ، أو مع منتج متقاطع ( from ... from ...) وبعد ذلك. إذا كنت تقوم بإجراء LEFT JOIN ، فأضف جملة lambda Where بين متغير نطاق الصلة والمكالمة DefaultIfEmpty() .
  7. JOIN شروط JOIN التي تعد متعددة واختبارات المساواة بين الجدولين إلى كائنات مجهولة
  8. يتم محاكاة LEFT JOIN باستخدام into joinvariable والقيام بعمل آخر من joinvariable متبوعًا بـ .DefaultIfEmpty() .
  9. استبدال COALESCE مع عامل الشرطية ( ?: null واختبار null .
  10. ترجمة IN إلى .Contains() NOT IN ! ... Contains() ، باستخدام المصفوفات الحرفية أو متغيرات الصفيف لقوائم ثابتة.
  11. ترجم x BETWEEN منخفض وعالي إلى منخفض <= x && x <= مرتفع .
  12. ترجمة CASE إلى العامل الشرطي الثلاثي ?: .
  13. يجب استبدال SELECT * بـ select range_variable أو وصلات ، كائن مجهول يحتوي على جميع متغيرات النطاق.
  14. يجب استبدال حقول SELECT select new { ... } لإنشاء كائن مجهول مع جميع الحقول أو التعبيرات المطلوبة.
  15. ترجمة IIF إلى عامل التشغيل الشرطي الثلاثي C #.
  16. يجب التعامل مع FULL OUTER JOIN السليم مع طريقة التمديد.
  17. ترجمة UNION إلى Concat ما لم يكن كلا الاستعلامات الفرعية Concat ، في هذه الحالة يمكنك الترجمة إلى 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 });




sql-to-linq-conversion