SQL到LINQ,具有多个连接、计数和左连接

okxuctiv  于 2023-01-06  发布在  其他
关注(0)|答案(2)|浏览(163)

我用多个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

然而,我希望这个请求的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)
              };

我尝试修改this SO question,但无法解决。我对分组子请求中的Count感到困惑。
谁能解释一下我哪里错了?
专业提示:如果有人能用lambda表达式写出等价的表达式,那就加分了

fae0ux8s

fae0ux8s1#

要将SQL转换为LINQ查询解析:
1.将子选择转换为单独声明的变量 *,除非它们引用子选择 * 外部的列,在这种情况下,使用括号创建子查询。
1.按照LINQ子句顺序翻译每个子句,将一元和聚合运算符(DISTINCTTOPMINMAX等)翻译为应用于整个LINQ查询的函数。
1.使用表别名作为范围变量。使用列别名作为匿名类型字段名。
1.对多个列使用匿名类型(new { ... })(例如在groupby中)。
1.使用First().fieldgroupby聚合范围变量获取非键值。
1.使用EF或EF Core时,可能使用.Include()JOIN子句转换为导航属性。
1.否则,作为两个表之间的多个AND艾德相等测试的JOIN子句应转换为equals每一端的匿名对象。

  1. JOIN条件如果不都是使用AND进行的相等性测试,则必须使用连接外部的where子句或使用叉积来处理(from ... from ...),然后是where。如果您正在执行LEFT JOIN,在连接范围变量和DefaultIfEmpty()调用之间添加一个lambda Where子句。
    1.通过使用intojoinvariable 并执行另一个fromjoinvariable 后跟.DefaultIfEmpty())来模拟LEFT JOIN
    1.将FROM子句中的多个表转换为多个from子句。
    1.将FROM T1 CROSS APPLY T2转换为两个from子句,一个用于T1,另一个用于T2
    1.将FROM T1 OUTER APPLY T2转换为两个from子句,一个用于T1,另一个用于T2,但将.DefaultIfEmpty()添加到T2
    1.将COALESCE替换为条件运算符(?:)和null测试。
    1.使用常量列表的文本数组或数组变量,将IN转换为.Contains(),将NOT IN转换为! ... Contains()
    1.将 xBETWEEN * 低 * AND * 高 * 转换为 * 低 * <=x&&x<= * 高 *。
    1.将CASEISNULLIIF转换为三元条件运算符?:
  2. SELECT *必须替换为select range_variable,对于连接,则为包含所有范围变量的匿名对象。
  3. SELECT列必须替换为select new { ... },从而创建一个包含所有所需字段或表达式的匿名对象。
    1.通过重复表达式或在首次使用表达式之前使用let命名表达式,可以转换对计算SELECT列的引用。
    1.正确的FULL OUTER JOIN必须用extension method处理。
    1.将UNION转换为Concat,除非两个子查询都是DISTINCT,在这种情况下,您可以转换为Union,而忽略DISTINCT
    1.使用单例GroupBy转换没有GROUP BY的聚合查询:添加.GroupBy(r => 1),然后转换Select中的聚合函数。
    1.日期数学和其他一些canonical函数可以使用EF.Functions来访问,以获取DbFunctions类(EF Core)、EntityFunctions类(EF〈6)或DbFunctions的示例来访问静态方法(EntityFramework 6.x)。
    1.使用(EF核心〉= 2)EF.Functions.Like(column, pattern)或(EF 6.x)DbFunctions.Like(column, pattern)转换SQL LIKE表达式。
    将这些规则应用于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 });
kb5ga3dv

kb5ga3dv2#

使用LINQ Me Up的(正在开发的)版本:我正在开发的一个人工智能支持的SQL到LINQ转换工具,答案是:

var query = (from c in TABLE_C join v in TABLE_V on c.Id equals v.Id join r in (from r in TABLE_R group r by r.Id into g select new { Id = g.Key, cnt = g.Count() }) on c.Id equals r.Id into r_join from r in r_join.DefaultIfEmpty() where c.IdUser == "1234" group new { c, v, r } by new { c.Id, c.Title, r.cnt } into g select new { Id = g.Key.Id, Title = g.Key.Title, Nb_V2 = g.Count(v => v.v.Id), Nb_V1 = g.Select(v => v.v.IdUser).Distinct().Count(), Nb_R = g.Key.cnt }).Distinct(); 
// Execute the LINQ query var result = query.ToList();

相关问题