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

为何未用Include()时EF Core仍关联表?如何执行无关联查询?

EF Core 5:未使用Include却担心关联表的问题解析

问题背景

我正在使用Entity Framework Core 5版本,定义了如下实体类:

public class BusinessTransaction
{
    public Guid Id { get; set; }
    public Guid BusinessId { get; set; }

    public int Amount { get; set; }
    public bool IsPay { get; set; }
    public DateTime Date { get; set; }

    public string Title { get; set; }
    public long Time { get; set; }
    public string TrackingCode { get; set; }

    [ForeignKey(nameof(BusinessId))]
    public Businesses.Business Business { get; set; } 
}

执行如下查询获取数据时,感觉Entity Framework Core在未使用Include()的情况下关联了Business表:

public async Task<List<BusinessTransaction>> GetTransactionByBusienssId(Guid id, int skip = 0, int take = 10)
{
    var query = DbContext.BusinessTransactions
                         .Where(b => b.BusinessId == id)
                         .OrderByDescending(b => b.Date)
                         .Skip(skip)
                         .Take(take);

    return await query.ToListAsync();
}

实际SQL Server执行的查询语句(已格式化):

DECLARE @__id_0 uniqueIdentifier = '2af03a2e-17b6-4708-ceee-08da1fc18b20';
DECLARE @__p_1 int = 0;
DECLARE @__p_2 int = 10;
    
SELECT
    [b].[Id],
    [b].[Amount],
    [b].[BusinessId],
    [b].[Date],
    [b].[IsPay],
    [b].[Time],
    [b].[Title],
    [b].[TrackingCode]
FROM
    [BusinessTransactions] AS [b]
WHERE
    [b].[BusinessId] = @__id_0
ORDER BY
    [b].[Date] DESC
OFFSET
    @__p_1 ROWS FETCH NEXT @__p_2 ROWS ONLY;

问题原因

从生成的SQL语句可以明确判断:EF Core并没有关联Business表。你产生误解的原因是实体类中定义了Business导航属性,但这只是EF Core的实体关系配置,不会自动触发关联查询。

EF Core的关联查询触发逻辑非常明确:只有满足以下任一条件时,才会执行关联查询:

  • 使用Include()/ThenInclude()显式指定加载导航属性;
  • 启用了延迟加载,且后续代码访问了BusinessTransaction.Business属性;
  • 使用了显式加载(如LoadAsync())。

当前你的查询既没有调用Include,生成的SQL也没有任何JOIN语句,完全是单表查询,不存在意外关联的情况。

确保不关联任何相关表的方案

如果要彻底杜绝意外关联的可能性,可以采用以下几种方式:

  • 禁用延迟加载:如果你的DbContext启用了延迟加载(比如配置了UseLazyLoadingProxies(),或者导航属性加了virtual关键字),后续代码一旦访问Business属性,EF Core会自动发起额外查询。可以移除延迟加载配置,或者去掉导航属性的virtual修饰符(针对代理延迟加载)。
  • 使用DTO替代实体类:如果业务不需要访问Business导航属性,直接定义仅包含所需字段的DTO,查询时通过Select()映射到DTO,这样EF Core不会处理任何导航属性相关逻辑:
    public class TransactionDto
    {
        public Guid Id { get; set; }
        public Guid BusinessId { get; set; }
        public int Amount { get; set; }
        public bool IsPay { get; set; }
        public DateTime Date { get; set; }
        public string Title { get; set; }
        public long Time { get; set; }
        public string TrackingCode { get; set; }
    }
    
    public async Task<List<TransactionDto>> GetTransactionByBusinessId(Guid id, int skip = 0, int take = 10)
    {
        return await DbContext.BusinessTransactions
                             .Where(b => b.BusinessId == id)
                             .OrderByDescending(b => b.Date)
                             .Skip(skip)
                             .Take(take)
                             .Select(b => new TransactionDto
                             {
                                 Id = b.Id,
                                 BusinessId = b.BusinessId,
                                 Amount = b.Amount,
                                 IsPay = b.IsPay,
                                 Date = b.Date,
                                 Title = b.Title,
                                 Time = b.Time,
                                 TrackingCode = b.TrackingCode
                             })
                             .ToListAsync();
    }
    
  • 避免触发导航属性访问:如果必须保留实体类中的导航属性,确保后续代码不会访问Business属性,也不启用任何自动加载机制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 09:45:49