Вставка нескольких записей одновременно в ядро Entity Framework 6

#postgresql #entity-framework-core #npgsql

Вопрос:

Я работаю с минимальным API .NET Core 6 с базой данных PostgreSQL 13. Пакеты, которые я использую Microsoft.EntityFrameworkCore , 6.0.0 и Npgsql.EntityFrameworkCore.PostgreSQL . У меня есть настройки LogLevel.Information , чтобы я мог просматривать запросы SQL, создаваемые ядром Entity Framework, по мере его взаимодействия с базой данных.

Я замечаю, что, когда я вставляю записи через свою конечную точку, она выполняет серию отдельных операторов вставки вместо ожидаемого (VALUES (<row1 values>),(<row2 values>)) формата. Например, это ведение журнала:

 INSERT INTO <mytable> (<columns>) VALUES (<row1 values>);
INSERT INTO <mytable> (<columns>) VALUES (<row2 values>);
 

Это мой код для вставки:

 context.Items.AddRange(list);
await context.SaveChangesAsync();
 

Есть ли способ объединить все значения в один INSERT запрос?

Ответ №1:

@святослав-данилов ответ не точен.

EF Core пакует все вставки/обновления: при выполнении сохранений в DbContext все накопленные изменения отправляются с помощью одной команды в один оборот (для этого можно использовать средство поиска пакетов, такое как wireshark).

Обратите внимание, что в некоторых ситуациях это может быть эффективнее, чем один запрос ВСТАВКИ, так как инструкции множественных вставок параметризованы и имеют идентичный SQL, поэтому одну и ту же подготовленную инструкцию можно использовать повторно.

Тем не менее, если вы массово импортируете огромное количество записей, возможно, все же стоит использовать поддержку низкоуровневого КОПИРОВАНИЯ Npgsql. Я настоятельно рекомендую написать быстрый тест с помощью BenchmarkDotNet и сравнить различные решения с вашим собственным сценарием.

Комментарии:

1. Что ж, согласитесь с этим. Но обычно, когда у людей возникает вопрос «почему они не генерируют такой запрос», у них возникают проблемы с производительностью. Кроме того, в ядре EF невозможно запустить и забыть вставить, особенно если есть поля, созданные базой данных.

2. Несколько раундов против одного-это совсем другой вопрос, чем обновления «выстрели и забудь». В PostgreSQL поля, созданные базой данных (например, идентификаторы), извлекаются с помощью предложения RETURN, которое имеет очень мало накладных расходов, помимо фактической передачи значения (например, без дополнительных обходов), поэтому это вряд ли будет источником проблем с perf. В любом случае выше нет никаких указаний на проблему perf, просто вопрос о том, как выполняется вставка.

Ответ №2:

Именно так работает EF. Вы не можете ничего вставлять/обновлять/удалять без отслеживания изменений. И это неэффективно, если записей много. В PostgreSQL есть КОПИЯ для вставки большого количества записей, и если вы беспокоитесь о производительности, вы можете использовать такую возможность, предоставляемую Npgsql.

Хотя существует быстрый способ вставки записей, это механизм очень низкого уровня, который требует больших усилий и точного сопоставления, чтобы он работал.

Таким образом, существует множество расширений ядра EF, которые могут заставить его работать с минимальными усилиями. Одним из них является linq2db.EntityFrameworkCore, обратите внимание, что я один из создателей, и мое мнение может быть субъективным.

После установки библиотеки вы можете просто позвонить BulkCopy , чтобы вставить пакет записей.

 await context.BulkCopyAsync(items);
 

Существуют также параметры настройки, которые могут повысить производительность.