У меня есть функция в моей системе, которая позволяет пользователю создавать сценарии из данных.Для этого мне нужно скопировать данные из одного сценария в другой, изменив идентификаторы и внешние ключи, чтобы сохранить согласованность.Я отлично справлялся с 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
, но не смог его сделать.Любая помощь приветствуется.Спасибо!