我有json数据与id,我的目标是采取json数据和插入数据库使用实体框架,与相同的id设置,因为我使用它们作为一个外键在不同的表。但问题是我得到了error
Microsoft.Data.SqlClient。当IDENTITY_INSERT设置为OFF时,无法在表'ProductTypes'中插入标识列的显式值
这意味着IDENTITY_INSERT
被设置为OFF
我不明白为什么我使用
dbContext.Database.ExecuteSqlRaw("SET IDENTITY_INSERT dbo.ProductTypes ON");
命令,以确保它被设置为on。
public class ApplicationDbContextSeed
{
public static async Task SeedAsync(ApplicationDbContext dbContext, ILoggerFactory loggerFactory)
{
try
{
if (!dbContext.ProductTypes.Any())
{
var typesData = File.ReadAllText("../Infrastructure/Data/SeedData/types.json");
var types = JsonSerializer.Deserialize<List<ProductType>>(typesData);
dbContext.Database.ExecuteSqlRaw("SET IDENTITY_INSERT dbo.ProductTypes ON");
foreach (var item in types)
{
dbContext.ProductTypes.Add(item);
}
await dbContext.SaveChangesAsync();
dbContext.Database.ExecuteSqlRaw("SET IDENTITY_INSERT dbo.ProductTypes OFF");
}
}
catch (Exception ex)
{
var logger = loggerFactory.CreateLogger<ApplicationDbContextSeed>();
logger.LogError(ex.Message);
}
}
}
EF默认情况下将为每个语句打开/关闭连接,因此您的SET IDENTITY_INSERT在SaveChanges之前无法存活。如果您强制打开连接,DbContext将对所有操作使用打开的连接,并在DbContext被处置时为您关闭连接。
,
using var db = new Db();
var con = db.Database.GetDbConnection();
con.Open();
db.Database.ExecuteSqlRaw("drop table if exists test; create table test(id int identity, a int)");
db.Database.ExecuteSqlRaw("set identity_insert test on");
db.Database.ExecuteSqlRaw("insert into test(id,a) values (1,1)");
Console.WriteLine("done");
如果键列声明为"Id"或者带有"id";那么EF将自动假定这些是DB将填充的标识列。
如果表总是由外部源填充,并且您不需要创建期望生成ID的行,则需要考虑一个选项:将EF配置为而不是期望标识:
。在DbContext.OnModelCreating
上使用modelBuilder
:
modelBuilder.Entity<ProductType>(e =>
{
e.HasKey(x => x.Id)
.Property(x => x.Id)
.HasDatabaseGenerated(DatabaseGeneratedOption.None);
});
这告诉EF期望插入记录的代码提供ID。这意味着从列中删除Identity。如果应用程序将创建产品类型,那么最好配置一个单独的DbContext与上述禁用的标识(加上迁移禁用,如果你使用那些与你的主应用程序DbContext),并发出一个临时的直接SQL语句,在插入操作之前启用标识插入,然后关闭标识插入。