【问题标题】:How to create Linq2Sql query that will group records from linked table and calculate 2 count fields如何创建将从链接表中分组记录并计算 2 个计数字段的 Linq2Sql 查询
【发布时间】:2016-05-07 12:47:29
【问题描述】:

在这里我找到了如何使用 Linq2Sql 连接表并计算链接记录的数量LINQ - Left Join, Group By, and Count

我已经实现了它,它对我来说没问题:以下表达式

var v = from c in db.GetTable<Country>()
        join t0 in db.GetTable<Team>() on c.Id equals t0.CountryId into t1
        from team in t1.DefaultIfEmpty()
        group team by c.Id into teamsGrouped
        select new CountryTeamsInfo
            {
                CountryId = teamsGrouped.Key,
                TeamsTotal = teamsGrouped.Count(),
                // TeamsWithoutOwnerFree = teamsGrouped.Count(t => t.OwnerId==0)
            }
            ;
         List<CountryTeamsInfo> res = v.ToList();

生成以下查询:

SELECT c.Id, Count(*) as c1
FROM countries c
LEFT JOIN teams t1 ON c.Id = t1.Country
GROUP BY c.Id 

事实上,我还需要计算那些 OwnerId 字段不等于 0 的链接器记录。

看起来我应该在 linq 表达式 (TeamsWithoutOwnerFree = teamsGrouped.Count(t => t.OwnerId==0)) 中取消注释该行,但这不起作用,尝试执行会导致错误:

给定的键不在字典中

查询没有出现在 SQL 日志文件中,我无法在调试器中检查它。

什么是计算“团队”表中符合附加条件的行的正确方法。

附:如果重要的话,我会使用 C# 4.0、MySql 5.1 和 BLToolkit 4.1

【问题讨论】:

  • 奇怪,它应该可以工作。错误的堆栈跟踪是什么?

标签: c# mysql linq-to-sql bltoolkit


【解决方案1】:

也许可以尝试使用GroupJoin() 进行查询:

var result = db.GetTable<Country>()
               .GroupJoin(db.GetTable<Team>(),
                   c => c.Id,
                   t => t.CountryId,
                   (country, teams) => new
                   {
                       CountryId = country.Id,
                       TeamsTotal = teams.Count(),
                       TeamsWithoutOwnerFree = teams.Count(t => t.OwnerId == 0)
                   })
               .ToList();

【讨论】:

  • 谢谢,会试试的。您能否还建议将扩展方法“翻译”为 GroupJoin 的 linq2sql?谢谢
  • @Budda,我不太明白这个问题 - “从扩展方法转换为 linq2sql”是什么意思?
  • 我只是想用 Linq2Sql 语法(如我原来的帖子)写同样的东西,而不是基于 ExtensionMethods 的语法,但这没什么大不了的。
  • 我已经检查了您的建议,看起来执行问题已解决。但是生成的查询仍然没有组件来计算'TeamsWithoutOwnerFree'...
  • 看来我应该编写一个额外的“查询”来获取那些拥有 OwnerId==0 的团队。会尝试
【解决方案2】:

在 RePierre 的帮助下,我找到了正确的查询:

var v = db.GetTable<Country>().Where(country => country.Allowed)
                    .GroupJoin(
                        db.GetTable<Team>(),
                        country => country.Id,
                        team => team.CountryId,
                        (country, teams) => new CountryTeamsInfo
                                                {
                                                    CountryId = country.Id,
                                                    TeamsTotal = teams.Count(),
                                                    TeamsWithoutOwnerFree = teams.Count(t => t.OwnerId != 0),
                                                }
                    ).GroupJoin(
                        db.GetTable<Team>().Where(te=>te.OwnerId==0),
                        cti => cti.CountryId,
                        team => team.CountryId,
                        (cti, teams) => new CountryTeamsInfo
                        {
                            CountryId = cti.CountryId,
                            TeamsTotal = cti.TeamsTotal,
                            TeamsWithoutOwnerFree = teams.Count(t => t.OwnerId != 0),
                        }
                    )
                    ;

我担心它使用 2 个子查询...会尝试优化它。任何想法都会很棒

附:实际上,生成的 SQL 查询看起来也很丑:

SELECT
cti.Id as Id1,
cti.c1 as c11,
(
    SELECT
        Count(*)
    FROM
        teams te
    WHERE
        cti.Id = te.Country AND te.User = 0
) as c2
FROM
(
    SELECT
        country.Id,
        (
            SELECT
                Count(*)
            FROM
                teams t1
            WHERE
                country.Id = t1.Country
        ) as c1
    FROM
        countries country
    WHERE
        country.allow

【讨论】:

  • 您不应该担心它使用两个子查询,因为 linq to sql 使用延迟执行 - 这意味着只有一个查询进入数据库。从这个角度来看,您可以根据自己的喜好拆分查询,以保持编码风格并提高可读性。
  • 如果CountriesTeams 之间存在父子关系,您可以尝试这种方法pastebin.com/KzG68fEP
【解决方案3】:

这是在我的环境中工作的查询:

from c in db.GetTable<Country>()
where c.Allowed
select new CountryTeamsInfo
{
    CountryId = c.Id,
    TeamsTotal = db.GetTable<Team>().Count(t => t.CountryId == c.Id && t.Allowed),
    TeamsHasOwner = db.GetTable<Team>().Count(t => t.CountryId == c.Id && t.Allowed && t.OwnerId != 0),
}

不是最好的解决方案(我需要在每个子查询中重复团队选择标准 t.Allowed),但仍然可以正常工作并且生成的 SQL 也很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 2022-10-01
    • 2011-04-23
    • 1970-01-01
    • 2019-07-13
    • 2015-03-05
    • 1970-01-01
    相关资源
    最近更新 更多