我正在使用 EFCore.BulkExtensions lib 版本 6.7.0 和 EntityFrameworkCore 6.0.13,试图重现文档中解释的以下行为:
using (var transaction = context.Database.BeginTransaction())
{
context.BulkInsert(entities, new BulkConfig { SetOutputIdentity = true });
foreach (var entity in entities) {
foreach (var subEntity in entity.ItemHistories) {
subEntity.ItemId = entity.ItemId; // sets FK to match its linked PK that was generated in DB
}
subEntities.AddRange(entity.ItemHistories);
}
context.BulkInsert(subEntities);
transaction.Commit();
}
entity.ItemId
应该用数据库生成的PK更新。
我无法用下面的代码重现它,结果总是:
[ENTITY ID]: 0
using (var transaction = dbContext.Database.BeginTransaction())
{
var entities = entitiesEnumerable.ToList();
foreach (var e in entities)
{
e.Id = default;
}
var bulkConfig = new BulkConfig
{
SetOutputIdentity = true
};
await dbContext.BulkInsertAsync(entities, bulkConfig);
foreach (var e in entities)
{
_logger.LogWarning($"[ENTITY ID]: {e.Id}");
}
transaction.Commit();
}
我的实体有如下属性作为PK,底层数据库是SQL Server:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
问题似乎与批量插入操作后如何访问生成的身份有关。带有 SetOutputIdentity 选项的 BulkInsert 操作将在插入操作完成后使用生成的标识值更新实体的 Id 属性。
但是,在您的代码中,您在批量插入操作后立即迭代实体并访问 Id 属性。此时 Id 值可能尚未更新,这就是为什么您始终将 0 作为值的原因。
要解决此问题,您可以尝试等待批量插入操作完成,然后再访问更新后的 Id 值。您可以使用 await dbContext.BulkInsertAsync(entities, bulkConfig) 方法等待批量插入操作完成,然后遍历实体以访问更新后的 Id 值。这是一个例子:
using (var transaction = dbContext.Database.BeginTransaction())
{
var entities = entitiesEnumerable.ToList();
foreach (var e in entities)
{
e.Id = default;
}
var bulkConfig = new BulkConfig
{
SetOutputIdentity = true
};
await dbContext.BulkInsertAsync(entities, bulkConfig);
await dbContext.SaveChangesAsync(); // Wait for the bulk insert operation to complete
foreach (var e in entities)
{
_logger.LogWarning($"[ENTITY ID]: {e.Id}");
}
transaction.Commit();
}
通过在批量插入操作之后调用 await dbContext.SaveChangesAsync(),您可以确保在访问它们之前更新 Id 值。