考虑我有以下数据库查询:
var entries = (await db.ScheduleEntries
.Where(se => se.ClassId == studentsClassId)
.OrderBy(se => se.LessonNumber)
.Select(se => new
{
se.DayOfWeek,
Entry = new ScheduleEntryDto
{
Id = se.Id,
LessonNumber = se.LessonNumber,
HostTeacher = se.EntryStub.TeacherFullname,
Location = se.EntryStub.Location,
SchoolClass = $"{se.Class.ClassNumber} {se.Class.ClassLetter}",
SubjectName = se.EntryStub.Subject.Name
// And other fields
// But ScheduleEntryDto doesn't contain DayOfWeek field
}
})
.ToArrayAsync())
.GroupBy(rse => rse.DayOfWeek)
.ToDictionary(g => g.Key, g => g.Select(a => a.Entry).ToArray());
EF Core 生成良好的 SQL 查询,该查询执行必要的
JOIN's
并使用 SELECT
仅获取必需的字段。
但是这段代码看起来很大,不是吗?因此,我决定创建一个自动映射器配置文件以将 db ScheduleEntry 模型映射到 ScheduleEntryDto:
var entries = (await db.ScheduleEntries
.Where(se => se.ClassId == studentsClassId)
.OrderBy(se => se.LessonNumber)
.Select(se => new
{
se.DayOfWeek,
Entry = mapper.Map<ScheduleEntryDto>(se)
})
.ToArrayAsync())
.GroupBy(rse => rse.DayOfWeek)
.ToDictionary(g => g.Key, g => g.Select(a => a.Entry).ToArray());
但是此代码失败并出现“命令已在进行中”异常。而且它还会产生奇怪的 SQL,没有任何
JOIN's
。
我发现的可能解决方案 - 是
Include()
和 ThenInclude()
所有必需的表,但我必须自己编写所有 Includes,它还会生成 SQL 查询,从而获取许多不必要的字段。这些 Includes 再次使代码变得庞大。
我发现,如果按照我的方式将
.Map<>()
包装在 .Select()
方法中,EF Core 不会执行必要的 JOIN's
。
但是,如果我首先
.ProjectTo()
,评估查询,然后执行 .GroupBy()
DayOfWeek,则一切正常。但是 ScheduleEntryDto
不包含 DayOfWeek 字段,所以我不能这样做。
那我该怎么办?
使用 EF 查询时,不会查询数据库,直到出现“.ToList()”、“.ToListAsync()”等提示,在您的情况下,提示看起来是“.ToArrayAsync()”,所以您要求的是EF 从自动映射器生成 SQL,这是不可能的,从语法上讲,在您的 IDE 中它是正确的,但 EF 不支持这一点。
在我看来,初始查询没有任何问题,除了在多个表上尝试使用拆分查询之外,但这有时会返回不同的结果,因此值得测试。