You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Razor Pages脚手架生成的EF Core关联查询?

解决EF关联查询加载冗余字段的最小改动方案

嘿,这个问题我之前也遇到过——脚手架生成的代码确实会默认加载关联实体的所有字段,不过我们只需要微调查询逻辑就能搞定,而且改动非常小,完全不用动实体类或者其他核心代码。

1. 用投影查询精准选择字段(最推荐,改动最少)

首先找到你在Todo详情页/编辑页里获取数据的代码(一般在Controller或者PageModel的Details/Edit方法里),原来的代码大概是这样的:

var todo = await _context.Todos
    .Include(t => t.Category)
    .FirstOrDefaultAsync(t => t.Id == id);

只需要把这段代码改成投影查询,明确指定要加载的Category字段:

// 用匿名类型临时存储需要的数据,不用额外定义类
var todoData = await _context.Todos
    .Where(t => t.Id == id)
    .Select(t => new {
        // 保留Todo的所有字段
        t.Id,
        t.Description,
        t.DueDate,
        t.CategoryId,
        // 只加载Category需要的字段
        CategoryName = t.Category.Name
    })
    .FirstOrDefaultAsync();

之后在视图里,直接用todoData.CategoryId和todoData.CategoryName就可以了,完全不需要用到DummyData。如果想要强类型(避免视图里用匿名类型的麻烦),可以加个超简单的DTO类(这也算极小的改动):

// 新建一个只存必要数据的DTO类
public class TodoViewDto
{
    public int Id { get; set; }
    public string Description { get; set; }
    public DateTime? DueDate { get; set; }
    public int CategoryId { get; set; }
    public string CategoryName { get; set; }
}

然后查询改成返回这个DTO:

var todoDto = await _context.Todos
    .Where(t => t.Id == id)
    .Select(t => new TodoViewDto {
        Id = t.Id,
        Description = t.Description,
        DueDate = t.DueDate,
        CategoryId = t.CategoryId,
        CategoryName = t.Category.Name
    })
    .FirstOrDefaultAsync();

这样生成的SQL就会自动去掉DummyData,只查询你需要的字段:

SELECT [t].[Id], [t].[Description], [t].[DueDate], [t].[CategoryId], [c].[Name]
FROM [Tasks] AS [t]
INNER JOIN [Categories] AS [c] ON [t].[CategoryId] = [c].[Id]
WHERE [t].[Id] = @id

2. EF Core专属:用Include+ThenSelect限制加载字段(适合不想改返回类型的场景)

如果你用的是EF Core 5及以上版本,还可以用Include配合ThenSelect来筛选关联实体的字段,但注意这种方式需要返回一个包含部分属性的Category对象(不能直接返回原始的Todo实体,因为实体的导航属性要求完整对象):

var todo = await _context.Todos
    .Where(t => t.Id == id)
    .Select(t => new {
        Todo = t,
        Category = new { t.Category.Id, t.Category.Name }
    })
    .FirstOrDefaultAsync();

这种方式同样能生成只包含必要字段的SQL,而且不用新建太多额外代码。

为啥不直接删实体里的DummyData?

看你说应用运行正常,说明这个字段大概率在其他地方有用,所以绝对不能直接删实体属性——投影查询的好处就是完全不影响其他功能,只在需要的页面限制加载字段。

内容的提问来源于stack exchange,提问作者Sudhashbahu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 13:57:48