BulkInsert抛出“值不能为空。参数名称:成员”

时间:2019-09-26 11:38:25

标签: c# entity-framework .net-core ef-core-2.2 ef-bulkinsert

我的系统中有一个功能,允许用户从数据中创建场景。 为此,我需要将数据从一种情况复制到另一种情况,并更改ID和外键以保持一致性。 我自己使用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代码,但无法成功。 任何帮助表示赞赏。谢谢!

0 个答案:

没有答案
相关问题