EF Core Bulk Extensions: Index was out of range on BulkInsert

bulkinsert c# entity-framework entity-framework-core

Question

I am getting the following error while using bulk insert from EF core bulk extensions:

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](IList1 entities, IList1 entitiesWithOutputIdentity) at EFCore.BulkExtensions.TableInfo.LoadOutputData[T](DbContext context, IList1 entities) at EFCore.BulkExtensions.SqlBulkOperation.Merge[T](DbContext context, IList1 entities, TableInfo tableInfo, OperationType operationType, Action1 progress) at EFCore.BulkExtensions.DbContextBulkExtensions.BulkInsert[T](DbContext context, IList1 entities, BulkConfig bulkConfig, Action1 progress)
at MyProject.Data.Repository.Repository1.CreateRange(List1 entities)

I have a parent entity and child entity. What I am trying to do is, first bulk insert parent and then assign Ids generated for parent to their children. Then bulk insert children.

CreateRange method:

public List<T> CreateRange(List<T> entities)
{
    var bulkConfig = new BulkConfig { PreserveInsertOrder = true, SetOutputIdentity = true };
    _dbContext.BulkInsert(entities, bulkConfig);
    return entities;
}

Bulk insert code:

// 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);

It's not always possible to reproduce this issue. I am not able to identify the condition for reproducing this issue.

1
0
2/7/2020 5:57:57 AM

Accepted Answer

The exception occurs due to the Ids being assigned before the bulk insert operation is conflicting with the Ids already existing in the database. The solution is to use Ids that are not in the database. For example, negative numbers. This can still preserve the order of insertion since what matters is the relative order between entities within the list to be inserted.

The modified code:

// 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);
0
2/7/2020 7:57:48 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow