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

Entity Framework中仅在非空int时使用Contains()的查询效率问询

问题:EF中获取待删除Country关联Campaign的最优查询方式

现有实体类定义如下:

public class Country : IOrganization
{
    public int Id { get; private set; }

    public ICollection<Campaign>? Campaigns { get; private set; }
}

public class Campaign : IOrganization
{
    public int Id { get; private set; }

    public State? State { get; private set; }
    public int? StateId { get; set; }

    public Country? Country { get; private set; }
    public int? CountryId { get; set; }
}

每个Campaign仅属于State或Country,不会同时属于两者或都不属于。我需要获取即将删除的Country关联的子Campaign集合,当前实现代码如下:

List<Country> deletedCountries = ChangeTracker.Entries<Country>()
    .Where(e => e.State == EntityState.Deleted)
    .Select(e => e.Entity).ToList();

List<Campaign> campaignsIndirectDelete = await Campaigns
        .Where(campaign => campaign.CountryId != null)
        .Where(campaign => deletedCountries
            .Select(country => country.Id)
            .Contains(campaign.CountryId!.Value))
        .ToListAsync();

请问这是否是实现该需求的最高效方式?

补充说明:上述代码位于DbContext.SaveChanges()/SaveChangesAsync()中,用于处理EF无法正确处理级联删除的场景,需先删除每个对象的子集合,再删除集合对象本身,这限制了实现方式。


分析与优化建议

你的当前实现功能上是正确的,但并非最优,可从以下两点优化:

  1. 避免加载完整的Country实体
    当前代码先把待删除的Country实体全部加载到内存再提取Id,会不必要地占用内存(尤其是待删除Country数量较多时)。直接从ChangeTracker中提取Id即可:

    var deletedCountryIds = ChangeTracker.Entries<Country>()
        .Where(e => e.State == EntityState.Deleted)
        .Select(e => e.Entity.Id)
        .ToList();
    
  2. 简化查询条件
    因为每个Campaign仅属于State或Country,且Contains查询只会匹配CountryId不为null的记录(deletedCountryIds是int类型集合,null无法匹配其中的值),所以可以去掉Where(campaign => campaign.CountryId != null)这个条件,减少SQL过滤逻辑。

优化后的完整代码:

var deletedCountryIds = ChangeTracker.Entries<Country>()
    .Where(e => e.State == EntityState.Deleted)
    .Select(e => e.Entity.Id)
    .ToList();

var campaignsIndirectDelete = await Campaigns
    .Where(campaign => deletedCountryIds.Contains(campaign.CountryId!.Value))
    .ToListAsync();

额外说明

  • 在EF Core 3.0及以上版本中,这种Contains查询会被自动优化为SQL的IN子句,执行效率很高。
  • 由于代码运行在SaveChangesAsync中,确保ChangeTracker已正确追踪到所有待删除的Country实体即可,无需额外处理上下文状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 14:57:48