Я пытаюсь провести модульное тестирование довольно простого метода репозитория, который извлекает некоторые объекты, соответствующие любому из предоставленного списка идентификаторов сопоставления строк.
Реализация использует расширение EF Extension WhereBulkContains
, и я указываю столбец сущности, которому WhereBulkContain
должен соответствовать, используя лямбду.
public List<MyEntity> GetEntitiesByMappingId(List<string> mappingIds)
{
if (!mappingIds?.Any() ?? true)
{
return new List<MyEntity>(0);
}
return this
.context.MyEntity
.AsNoTracking()
.Include(e => e.ExtraData)
.Include(e => e.OtherData)
.WhereBulkContains(mappingIds, e => e.MappingId)
.ToList();
}
Когда мой тест запускает этот метод, он завершается сбоем из-за следующего основного исключения.
System.Exception
Oops! The `SkipInsertForInternalFeatures` option is only available for SQL Server, and PostgreSQL.
at Z.BulkOperations.BulkOperation.()
at Z.BulkOperations.BulkOperation.Execute()
at Z.EntityFramework.Extensions.EntityBulkOperation`1.BulkInsert()
at .BulkInsert[T](BulkOperation`1 this, DbContext context, List`1 list, Boolean isManager, List`1 entitiesToUpdate, Type type, String typeName)
at .BulkInsert[T](DbContext this, BulkOperation`1 bulkOperation, IEnumerable`1 entities2, List`1 entitiesToUpdate)
at DbContextExtensions.BulkInsert[T](DbContext this, IEnumerable`1 entities, Action`1 bulkOperationFactory)
at Z.EntityFramework.Plus.WhereBulkContainsBuilder`1.BulkCopy(DbContext context, List`1 keyNames, IEnumerable`1 entities, Type type2)
at Z.EntityFramework.Plus.WhereBulkContainsBuilder`1.WhereBulkContains(DbContext context, String commandText, List`1 commandTableBuilders, Boolean isNotCTE, Boolean isNotSelectOnly)
at Z.EntityFramework.Plus.QueryHookCommandInterceptor.ApplyHook(DbCommand command, DbContext context, String hook, Boolean isNotCTE)
at Z.EntityFramework.Plus.QueryHookCommandInterceptor.ReaderExecuting(DbCommand command, DbCommandInterceptionContext`1 interceptionContext)
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
Это известное ограничение Усилия? Или я пропустил какую-то конфигурацию, которая должна позволить этому работать?
Я использую Effort.EF6 версии 2.2.17 и версию 8.103.0 Z.EntityFramework.Extensions и Z.EntityFramework.Plus.EF6.
Почему бы и нет .Where(e => mappingIds.Contains(e.MappingId))
?
@IvanPetrov нет, я использую entityframework-effort.net , который представляет собой абстракцию в памяти именно для модульного тестирования EF-кода.
@Мариус, да, я могу переключиться на использование базового варианта Where, но это означает, что я теряю многие преимущества производительности entityframework-extensions.net/… .
Никаких преимуществ нет. Эта библиотека использует хаки для выполнения вещей, которые просто не подходят для ORM и в какой-то момент неизбежно выходят из строя. Посмотрите на стек вызовов, чтобы понять, в чем заключается хак. Чтобы заставить вас поверить, что вы можете фильтровать по тысячам идентификаторов (вы не можете), эта библиотека пытается ОБЪЕМНО ВСТАВИТЬ ваши идентификаторы во временную таблицу с помощью SqlBulkCopy. После этого он выполнит INNER JOIN с исходной таблицей по идентификаторам, чтобы получить соответствующие строки. Вы получите лучшую производительность и более удобный в обслуживании код, если будете использовать свой собственный код ETL.
Что касается an in-memory abstraction precisely for unit testing EF code
EF Core уже имеет поставщика в памяти для базового тестирования, а поставщик SQLite можно использовать в режиме в памяти для тестирования более сложных запросов.
Сколько предметов изначально находится в mappingIds
? Учитывая, что предложение IN(@id1,..)
, сгенерированное .Where(x=>mappingIds.Contains(x.Id))
, работает с тысячами элементов, почему вы с самого начала пытаетесь фильтровать по более чем 1 тысяче отдельных идентификаторов? Что ты пытаешься сделать? Загрузить данные, например, на основе файла CSV?
Список поддерживаемых поставщиков для Z.EntityFramework.Extensions
из пакета NuGet:
Поддержка: SQL Server, MySQL, Oracle, PostgreSQL, SQLite и других!
и из репозитория на github:
Поддержка нескольких поставщиков SQL:
- SQL-сервер 2008+
- SQL Azure
- SQL компактный
- MySQL
- SQLite
- PostgreSQL
- Оракул
Effort.EF6 не указан ни в одном из поддерживаемых поставщиков.
Это объясняет сообщение об исключении, которое вы получаете:
System.Exception
Oops! The `SkipInsertForInternalFeatures` option is only available for SQL Server, and PostgreSQL.
at Z.BulkOperations.BulkOperation.()
Это иронично, поскольку обе библиотеки опубликованы одним и тем же человеком (не сказано, что созданы, в итоге оказалось много старых объектов с открытым исходным кодом).
@PanagiotisKanavos да, тоже был удивлен...
Упс! Опция
SkipInsertForInternalFeatures
доступна только для SQL Server и PostgreSQL. Я полагаю, вы не используете ни один из этих двух?