BulkInsert, бросающий "Значение не может быть нулевым. Имя параметра: член" - PullRequest
0 голосов
/ 26 сентября 2019

У меня есть функция в моей системе, которая позволяет пользователю создавать сценарии из данных.Для этого мне нужно скопировать данные из одного сценария в другой, изменив идентификаторы и внешние ключи, чтобы сохранить согласованность.Я отлично справлялся с EFCore сам по себе, но теперь у нас намного больше данных, и они с каждым часом становятся медленнее.Затем я пытаюсь использовать EFCore.BulkExtensions, чтобы помочь мне улучшить производительность.Один случай, который я застрял - это массовая вставка некоторых сущностей с их переводами.По сути, у меня есть следующие сущности, подобные:

// My book class
public class DbBook
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }

    public string Title { get; set; }

    public long ScenarioId { get; set; }

    public ICollection<DbBookTranslation> BookTranslations { get; set; } = new HashSet<DbBookTranslation>();    
}

// The book translation class, that contains translations for the book description in different languages
public class DbBookTranslation
{

    public long BookId { get; set; }

    public string Language { get; set; }

    public string Description { get; set; }
}

// Config class for book translation in order to configure its key and some other properties
public class DbBookTranslationMap
{
    public void Configure(EntityTypeBuilder<DbBookTranslation> builder)
    {
        builder.HasKey(a => new {a.Language, a.BookId});
    }
}

Затем у меня есть служба для копирования этих сущностей в новый сценарий.Процесс работает следующим образом:

// I open a transaction
using (var tr = _ctx.Database.BeginTransaction())
{

    // I get all the books from the old scenario
    var oldBooks = ctx.DbBooks.Where(o => o.ScenarioId == oldScenarioId).AsNoTracking().ToList();

    // I iterate through oldBooks setting their ID to a new one and the ScenarioId to the 
    // new one and add on a list for further inserting
    var newBooks = new List<DbBooks>();
    var i = 0;
    for (var b in oldBooks) 
    {
        b.ScenarioId = newScenarioId;
        b.Id = i++;
        newBooks.Add(b);
    }

    // Then I bulk insert it
    // !!THIS IS WHERE IT FAILS!!
    var bulkConfig = new BulkConfig { PreserveInsertOrder = true, SetOutputIdentity = true };
    _ctx.BulkInsert(newBooks, bulkConfig);

    // Then I iterate through the translations, setting the new Id with some reflection
    var newTranslations = new List<DbBookTranslation>();
    for (var b in newBooks) {
        for (var t in b.BookTranslations) {
            t.BookId = b.Id; // Its done with reflection in rly
            newTranslations.Add(t);
        }
    }

    // Then bulk insert the translations
    _ctx.BulkInsert(newTranslations, bulkConfig);

    tr.Commit();
}

Когда я пытаюсь сделать первый BulkInsertions из DbBook, происходит сбой со следующей ошибкой:

   Value cannot be null. Parameter name: member
   at System.Linq.Expressions.Expression.MakeMemberAccess(Expression expression, MemberInfo member)
   at EFCore.BulkExtensions.TableInfo.OrderBy[T](Expression`1 source, String ordering)
   at EFCore.BulkExtensions.TableInfo.QueryOutputTable[T](DbContext context, String sqlQuery)
   at EFCore.BulkExtensions.TableInfo.LoadOutputData[T](DbContext context, IList`1 entities)
   at EFCore.BulkExtensions.SqlBulkOperation.Merge[T](DbContext context, IList`1 entities, TableInfo tableInfo, OperationType operationType, Action`1 progress)
   at EFCore.BulkExtensions.DbContextBulkExtensions.BulkInsert[T](DbContext context, IList`1 entities, BulkConfig bulkConfig, Action`1 progress)
   at MyProjectData.Services.ScenarioCopyService.CopyScenarioEntities[T](IEnumerable`1 entitiesEnumerable, Int64 newScenarioId) in C:\Projects\VSTS\MyProject-dotnet\MyProject\MyProject.Data\Services\ScenarioCopyService.cs:line 204
   at MyProject.Data.Services.ScenarioCopyService.CopyScenario(Int64 newScenarioId, Int64 oldScenarioId) in C:\Projects\VSTS\MyProject-dotnet\MyProject\MyProject.Data\Services\ScenarioCopyService.cs:line 77

Как ни странно, еслиЯ не передаю BulkConfig первому BulkInsert, который работает.Объекты сохранены.Но затем второй BulkInsert завершается неудачно с UniqueKeyViolation, потому что BookIds установлены неправильно.

Я попытался отладить код EFCore.BulkExtensions, но не смог его сделать.Любая помощь приветствуется.Спасибо!

...