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

EF Core中已传参却遇SQL参数错误:IDENTITY_INSERT未生效

解决EF Core泛型种子初始化中SET IDENTITY_INSERT不生效的问题

问题场景

使用泛型仓储类SeedRepository<TEntity>执行数据种子初始化时,通过ctx.Set<TEntity>().FromSql($"SET IDENTITY_INSERT {recordName} ON;")设置标识列插入权限,但该命令未生效,报错提示无法插入显式标识值(因为IDENTITY_INSERT处于OFF状态)。手动将{recordName}替换为具体表名后可正常运行,且recordName与表名完全一致。

报错信息

Microsoft.EntityFrameworkCore.DbUpdateException
HResult=0x80131500
An error occurred while saving the entity changes. See the inner exception for details.

Source=Microsoft.EntityFrameworkCore.Relational

StackTrace:
[省略部分栈信息]
at PropertyServant.Data.Seeding.SeedRepository`1.d__0.MoveNext() in ...\SeedRepository.cs:line 27

Inner Exception 1:
SqlException: Cannot insert explicit value for identity column in table 'AccountRule' when IDENTITY_INSERT is set to OFF.

问题原因

  1. API用途错误:FromSql是EF Core用于构造返回实体查询的API,仅适用于返回数据集的SQL语句,而非执行SET IDENTITY_INSERT这类非查询命令。
  2. 延迟执行机制:FromSql返回的IQueryable会延迟执行,若未枚举结果(如调用ToList()),SQL命令根本不会发送到数据库。
  3. 命令隔离:即使强制执行了FromSql命令,EF Core的批处理机制可能将设置命令与后续插入命令分开发送,导致两者不在同一个数据库会话,设置无法作用于插入操作。

解决方案

方案1:使用ExecuteSqlRawAsync执行非查询命令

将FromSql替换为专门执行非查询命令的ExecuteSqlRawAsync,确保命令立即执行,且与后续插入操作处于同一连接会话。

修改后的完整代码:

public class SeedRepository<TEntity> where TEntity : class
{
    public async Task Seed(IDbContextFactory<PropertyServantContext> contextFactory, List<TEntity> data)
    {
        string recordName = typeof(TEntity).Name;
        Log.Logger.Information("Seeding {0}", recordName);

        using (var ctx = contextFactory.CreateDbContext())
        {
            if (await ctx.Set<TEntity>().AnyAsync()) return;

            try
            {
                await ctx.Database.OpenConnectionAsync();
                // 用ExecuteSqlRawAsync执行IDENTITY_INSERT开关命令
                await ctx.Database.ExecuteSqlRawAsync($"SET IDENTITY_INSERT {recordName} ON;");

                foreach (TEntity record in data)
                {
                    ctx.Set<TEntity>().Add(record);
                }

                await ctx.SaveChangesAsync();

                await ctx.Database.ExecuteSqlRawAsync($"SET IDENTITY_INSERT {recordName} OFF;");
            }
            catch (Exception ex)
            {
                Log.Logger.Error(ex.ToString());
                throw;
            }
            finally 
            { 
                await ctx.Database.CloseConnectionAsync(); 
            }
        }
    }
}

方案2:兼容自定义表名的增强处理

如果实体类通过[Table]特性自定义了表名(未直接使用类名),需从EF Core模型元数据中获取真实表名,避免不匹配:

// 替换原recordName的获取逻辑
var entityType = ctx.Model.FindEntityType(typeof(TEntity));
string recordName = entityType.GetTableName();

关键说明

  • ExecuteSqlRawAsync是EF Core官方推荐的非查询SQL执行API,会立即将命令发送到数据库,确保SET IDENTITY_INSERT设置在插入前生效。
  • 将同步的OpenConnection/CloseConnection替换为异步版本,符合方法async签名,避免线程阻塞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 04:00:01