EF Core 批量扩展:索引超出 BulkInsert 的范围
EF Core Bulk Extensions: Index was out of range on BulkInsert
我在使用来自 EF 核心批量扩展的批量插入时收到以下错误:
Index was out of range. Must be non-negative and less than the size of
the collection. (Parameter 'index') at
System.Collections.Generic.List1.get_Item(Int32 index) at
EFCore.BulkExtensions.TableInfo.UpdateEntitiesIdentity[T](IList
1
entities, IList1 entitiesWithOutputIdentity) at
EFCore.BulkExtensions.TableInfo.LoadOutputData[T](DbContext context,
IList
1 entities) at
EFCore.BulkExtensions.SqlBulkOperation.Merge[T](DbContext context,
IList1 entities, TableInfo tableInfo, OperationType operationType,
Action
1 progress) at
EFCore.BulkExtensions.DbContextBulkExtensions.BulkInsert[T](DbContext
context, IList1 entities, BulkConfig bulkConfig, Action
1 progress)
at MyProject.Data.Repository.Repository1.CreateRange(List
1 entities)
我有一个 parent 实体和 child 实体。我想要做的是,首先批量插入 parent,然后将为 parent 生成的 ID 分配给他们的 children。然后批量插入 children.
CreateRange
方法:
public List<T> CreateRange(List<T> entities)
{
var bulkConfig = new BulkConfig { PreserveInsertOrder = true, SetOutputIdentity = true };
_dbContext.BulkInsert(entities, bulkConfig);
return entities;
}
批量插入代码:
// Index parents. (Since PreserveInsertOrder = true is set.)
parents.ForEach(x => x.Id = parents.IndexOf(x) + 1);
_parentRepository.CreateRange(parents);
// parent-child relation mapping.
parents.ForEach(x => x.Children.ToList().ForEach(y => y.ParentId = x.Id));
var children = parents.SelectMany(x => x.Children).ToList();
// Index children. (Since PreserveInsertOrder = true is set.)
children.ForEach(x => x.Id = children.IndexOf(x) + 1);
_childRepository.CreateRange(children);
并非总能重现此问题。我无法确定重现此问题的条件。
在批量插入操作之前分配的Id与数据库中已有的Id冲突导致出现异常。解决方案是使用不在数据库中的 ID。例如,负数。这仍然可以保留插入顺序,因为重要的是要插入的列表中实体之间的相对顺序。
修改后的代码:
// Index parents with non-conflict keys. (Since PreserveInsertOrder = true is set.)
parents.ForEach(x => x.Id = parents.IndexOf(x) - parents.Count);
_parentRepository.CreateRange(parents);
// parent-child relation mapping.
parents.ForEach(x => x.Children.ToList().ForEach(y => y.ParentId = x.Id));
var children = parents.SelectMany(x => x.Children).ToList();
// Index children with non-conflict keys. (Since PreserveInsertOrder = true is set.)
children.ForEach(x => x.Id = children.IndexOf(x) - children.Count);
_childRepository.CreateRange(children);
我在使用来自 EF 核心批量扩展的批量插入时收到以下错误:
Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index') at System.Collections.Generic.List
1.get_Item(Int32 index) at EFCore.BulkExtensions.TableInfo.UpdateEntitiesIdentity[T](IList
1 entities, IList1 entitiesWithOutputIdentity) at EFCore.BulkExtensions.TableInfo.LoadOutputData[T](DbContext context, IList
1 entities) at EFCore.BulkExtensions.SqlBulkOperation.Merge[T](DbContext context, IList1 entities, TableInfo tableInfo, OperationType operationType, Action
1 progress) at EFCore.BulkExtensions.DbContextBulkExtensions.BulkInsert[T](DbContext context, IList1 entities, BulkConfig bulkConfig, Action
1 progress)
at MyProject.Data.Repository.Repository1.CreateRange(List
1 entities)
我有一个 parent 实体和 child 实体。我想要做的是,首先批量插入 parent,然后将为 parent 生成的 ID 分配给他们的 children。然后批量插入 children.
CreateRange
方法:
public List<T> CreateRange(List<T> entities)
{
var bulkConfig = new BulkConfig { PreserveInsertOrder = true, SetOutputIdentity = true };
_dbContext.BulkInsert(entities, bulkConfig);
return entities;
}
批量插入代码:
// Index parents. (Since PreserveInsertOrder = true is set.)
parents.ForEach(x => x.Id = parents.IndexOf(x) + 1);
_parentRepository.CreateRange(parents);
// parent-child relation mapping.
parents.ForEach(x => x.Children.ToList().ForEach(y => y.ParentId = x.Id));
var children = parents.SelectMany(x => x.Children).ToList();
// Index children. (Since PreserveInsertOrder = true is set.)
children.ForEach(x => x.Id = children.IndexOf(x) + 1);
_childRepository.CreateRange(children);
并非总能重现此问题。我无法确定重现此问题的条件。
在批量插入操作之前分配的Id与数据库中已有的Id冲突导致出现异常。解决方案是使用不在数据库中的 ID。例如,负数。这仍然可以保留插入顺序,因为重要的是要插入的列表中实体之间的相对顺序。
修改后的代码:
// Index parents with non-conflict keys. (Since PreserveInsertOrder = true is set.)
parents.ForEach(x => x.Id = parents.IndexOf(x) - parents.Count);
_parentRepository.CreateRange(parents);
// parent-child relation mapping.
parents.ForEach(x => x.Children.ToList().ForEach(y => y.ParentId = x.Id));
var children = parents.SelectMany(x => x.Children).ToList();
// Index children with non-conflict keys. (Since PreserveInsertOrder = true is set.)
children.ForEach(x => x.Id = children.IndexOf(x) - children.Count);
_childRepository.CreateRange(children);