繁体   English   中英

为什么Group By翻译成Order By Entity Framework?

[英]Why is Group By translating in Order By by Entity Framework?

我在 .NET 7 中使用实体框架。

我有 3 个实体:

  1. 其中包含ProfessorIdCourse
  2. 具有CourseId等的Grade
  3. Professor

我想获取所有分配给一位教授并且至少有 1 个等级与之关联的课程,并在Dictionary<string, CourseViewModel>中过滤它们,其中 string 是学期。

我写了以下 LINQ 查询:

var professorGradedCourses = _dbContext.Courses
            .Where(course => course.ProfessorId == professorId && course.Grades.Any())
            .Select(course => new CourseViewModel
            {
                Title = course.Title,
                Semester = course.Semester,
            })
            .GroupBy(course => course.Semester)
            .OrderBy(course => course.Key)
            .ToDictionary(group => group.Key, group => group.ToList());

当它执行时,我得到一个异常,说它不能被翻译。

如果我删除OrderBy并仅保留GroupBy ,它将起作用并且 Microsoft SQL 服务器中翻译的 SQL 是:

  SELECT [c].[Semester], [c].[Title]
  FROM [Courses] AS [c]
  WHERE [c].[ProfessorId] = @__professorId_0 
    AND EXISTS (SELECT 1
                FROM [Grades] AS [g]
                WHERE [c].[Id] = [g].[CourseId])
  ORDER BY [c].[Semester]

如您所见,它无论如何都会添加ORDER BY ,即使我已将其删除并仅保留GroupBy() 有人可以解释为什么会这样吗? 如果我想按降序排序怎么办? 同样奇怪的是,如果我删除GroupBy()并仅保留OrderBy()并将ToDictionary替换为ToList ,它会起作用并且会生成完全相同的查询(只是现在我无法在没有进一步操作的情况下真正使用结果)。

GroupBy分组依据:

对序列的元素进行分组。

GROUP BY分组依据:

一个 SELECT 语句子句,它将查询结果分成多组行,通常通过对每组执行一个或多个聚合来进行。 SELECT 语句每组返回一行。

它们不等同。 主要区别是 LINQ GroupBy按键返回一个集合,而 SQL GROUP BY按键返回一个元素(列)。

如果投影按键询问一个元素,则 EF Core 将 LINQ GroupBy转换为 SQL GROUP BY

// Get the number of course by semester
context
    .Courses
    .GroupBy(c => c.Semester)
    .Select(cs => new { Semester = cs.Key, Count = cs.Count() })
    .ToList();

翻译成:

SELECT [c].[Semester], COUNT(*) AS [Count]
FROM [Courses] AS [c]
GROUP BY [c].[Semester]

但是,如果投影询问多个元素,则 EF Core 将 LINQ GroupBy转换为 SQL ORDER BY并自行分组。

context
    .Courses
    .Select(c => new { c.Id, c.Semester })
    .GroupBy(c => c.Semester)
    .ToDictionary(cs => cs.Key, cs => cs.ToList());

翻译成:

SELECT [c].[Semester], [c].[Id]
FROM [Courses] AS [c]
ORDER BY [c].[Semester]

如果结果是:

学期 ID
2023年S1 1个
2023年S1 4个
2023 中二 2个
... ...

然后 EF Core 读起来像:

  1. 阅读第一行:学期是“2023 S1”
    • 没有组
    • 然后创建一个组并添加该行。
  2. 阅读第二行:学期是“2023 S1”
    • 关键是相同的先行元素
    • 然后在组中添加行
  3. 阅读第三行:学期是“2023 S2”
    • 关键是那个先例元素不同
    • 然后创建一个新组和行。
  4. 等等...

您了解排序的好处。


关于报错,不知道EF Core不行。 查询声音合法。 也许这不应该在这个时候实施。


关于您尝试的内容,将排序的分组枚举转换为字典。 这很奇怪,因为字典不可排序。 然后这对元素进行排序并将它们放在松散的位置。

如果Dictionary看起来是有序的,那是巧合,而不是功能。 在实习生中,字典按键排序元素有代码,一般是排序顺序......但不是每次都这样。

如果你想要一个排序的字典,你可以使用SortedDictyonary 但如果您需要自定义排序规则,这可能会很棘手,例如:

context
    .Courses
    .Select(c => new { c.Id, c.Semester })
    .GroupBy(c => c.Semester)
    .ToImmutableSortedDictionary(cs => cs.Key, cs => cs.ToList(), new ReverseComparer<string>());



public class ReverseComparer<T> : IComparer<T>
{
    private IComparer<T> _comparer = Comparer<T>.Default;

    public int Compare(T? x, T? y)
    {
        return _comparer.Compare(x, y) * -1;
    }
}

您遇到的异常很可能是由于实体框架无法将OrderBy子句转换为 SQL。 从数据库中检索数据后, OrderBy子句在 memory 中执行,这就是当您删除它并仅保留GroupBy子句时它起作用的原因。

但是,如果您想按降序对字典进行排序,只需对ToDictionary结果调用Reverse方法即可:

var professorGradedCourses = _dbContext.Courses
.Where(course => course.ProfessorId == professorId && course.Grades.Any())
.Select(course => new CourseViewModel
{
    Title = course.Title,
    Semester = course.Semester,
})
.GroupBy(course => course.Semester)
.OrderByDescending(course => course.Key)
.ToDictionary(group => group.Key,
group => group.ToList())
.Reverse();

这样,字典将根据学期降序排列。

试一试,让我知道它是如何为你工作的。

编辑:

将 IEnumerable 转换回字典应该像这样工作:

var professorGradedCourses = _dbContext.Courses
.Where(course => course.ProfessorId == professorId && course.Grades.Any())
.Select(course => new CourseViewModel
{
    Title = course.Title,
    Semester = course.Semester,
})
.GroupBy(course => course.Semester)
.OrderByDescending(course => course.Key)
.ToDictionary(group => group.Key,
group => group.ToList())
.Reverse()
.ToDictionary(pair => pair.Key,
pair => pair.Value);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM