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

EF Core 7如何无主键批量删除实体?基于其他列实现

问题:EF Core中无需主键批量删除IssueProvision实体

我写了下面的BulkDeleteIssueProvision方法,尝试通过AuthorityProvisionId、IssueId和TenantId这三个属性批量删除IssueProvision实体(没设置主键Id,因为需要从数据库获取这个值):

public async Task BulkDeleteIssueProvision(List<IssueProvision> issueProvision)
{
        if (issueProvision is {Count: > 0})
        {
            var dbContext = GetDbContext();
            EntityEntry<IssueProvision> issueProvisionDbContext = null; 

            foreach (var issueProvisionList in issueProvision)
            {
                issueProvisionDbContext = dbContext.Attach(new IssueProvision
                {
                    AuthorityProvisionId = issueProvisionList.AuthorityProvisionId,
                    IssueId = issueProvisionList.IssueId,
                    TenantId = issueProvisionList.TenantId
                });
            }

            issueProvisionDbContext.State = EntityState.Deleted;
            await dbContext.SaveChangesAsync(); 
        }
}

执行时抛出异常:

The property 'IssueProvision.Id' has a temporary value while attempting to change the entity's state to 'Deleted'. Either set a permanent value explicitly, or ensure that the database is configured to generate values for this property.

已知问题和表主键有关,想请教怎么不用实体主键实现批量删除?


解决方案

方法1:使用EF Core 7+的ExecuteDelete批量删除(推荐)

EF Core 7及以上版本支持直接对查询结果执行批量删除,无需先加载实体,也不依赖主键。可根据三个属性构建查询条件,一次性删除符合要求的记录:

public async Task BulkDeleteIssueProvision(List<IssueProvision> issueProvision)
{
    if (issueProvision is { Count: > 0 })
    {
        var dbContext = GetDbContext();
        // 提取需要删除的三元组集合
        var deleteConditions = issueProvision.Select(ip => new 
        { 
            ip.AuthorityProvisionId, 
            ip.IssueId, 
            ip.TenantId 
        }).ToList();

        // 构建批量删除查询
        await dbContext.IssueProvisions
            .Where(ip => deleteConditions.Any(dc => 
                dc.AuthorityProvisionId == ip.AuthorityProvisionId &&
                dc.IssueId == ip.IssueId &&
                dc.TenantId == ip.TenantId))
            .ExecuteDeleteAsync();
    }
}

方法2:直接执行原生SQL语句

如果你的EF Core版本低于7,可直接执行原生SQL实现批量删除,效率同样很高:

public async Task BulkDeleteIssueProvision(List<IssueProvision> issueProvision)
{
    if (issueProvision is { Count: > 0 })
    {
        var dbContext = GetDbContext();
        // 构造参数化SQL,避免SQL注入
        var parameters = new List<SqlParameter>();
        var conditions = new List<string>();

        for (int i = 0; i < issueProvision.Count; i++)
        {
            var ip = issueProvision[i];
            conditions.Add($"(@AuthId{i}, @IssueId{i}, @TenantId{i})");
            parameters.Add(new SqlParameter($"@AuthId{i}", ip.AuthorityProvisionId));
            parameters.Add(new SqlParameter($"@IssueId{i}", ip.IssueId));
            parameters.Add(new SqlParameter($"@TenantId{i}", ip.TenantId));
        }

        var sql = $"DELETE FROM IssueProvisions WHERE (AuthorityProvisionId, IssueId, TenantId) IN ({string.Join(", ", conditions)})";
        await dbContext.Database.ExecuteSqlRawAsync(sql, parameters.ToArray());
    }
}

方法3:将三个字段配置为复合主键(业务允许时)

如果AuthorityProvisionId、IssueId和TenantId的组合在表中是唯一的,可在EF Core模型配置里将它们设为复合主键,之后就能通过这三个字段直接标记实体删除:

// 在DbContext的OnModelCreating方法中配置
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<IssueProvision>()
        .HasKey(ip => new { ip.AuthorityProvisionId, ip.IssueId, ip.TenantId });
}

配置后,原方法可修改为正确处理批量删除(注意要给每个实体都标记Deleted状态,而非仅最后一个):

public async Task BulkDeleteIssueProvision(List<IssueProvision> issueProvision)
{
    if (issueProvision is { Count: > 0 })
    {
        var dbContext = GetDbContext();
        foreach (var ip in issueProvision)
        {
            var entity = new IssueProvision
            {
                AuthorityProvisionId = ip.AuthorityProvisionId,
                IssueId = ip.IssueId,
                TenantId = ip.TenantId
            };
            dbContext.Attach(entity).State = EntityState.Deleted;
        }
        await dbContext.SaveChangesAsync();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 03:04:59