Automapper 包裹在 Select() 中时不执行 JOIN

问题描述 投票:0回答:1

考虑我有以下数据库查询:

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 字段,所以我不能这样做。

那我该怎么办?

c# linq asp.net-core entity-framework-core automapper
1个回答
0
投票

使用 EF 查询时,不会查询数据库,直到出现“.ToList()”、“.ToListAsync()”等提示,在您的情况下,提示看起来是“.ToArrayAsync()”,所以您要求的是EF 从自动映射器生成 SQL,这是不可能的,从语法上讲,在您的 IDE 中它是正确的,但 EF 不支持这一点。

在我看来,初始查询没有任何问题,除了在多个表上尝试使用拆分查询之外,但这有时会返回不同的结果,因此值得测试。

EF拆分查询

© www.soinside.com 2019 - 2024. All rights reserved.