为何未用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
相关产品推荐
相关产品推荐

