Эффективный способ делать массовую вставку/обновление с помощью Entity Framework
У меня есть список объектов, и я хочу вставить их в базу данных. Если объект уже существует в базе данных, тогда он должен быть пропущен. Если его в базе данных, но с разными значениями, то его необходимо обновить.
Есть ли способ сделать это иначе, чем вызов db для каждого элемента?
Мой план состоит в том, чтобы попробовать вставить, если выбрано исключение исключительного ограничения на ключ, затем выполните обновление.
Ответы
Ответ 1
Просто не используйте Entity Framework в этом случае. Просто используйте хранимую процедуру (как зависит от версии/подхода, который вы используете с EF, вам может потребоваться расширить ваш DbContext
или добавить сопоставление из модели сущности).
Если вы используете SQL Server, то в своей процедуре хранилища используйте команду MERGE
, которая эффективно выполняет точно, что вам нужно: вставить, если оно не существует, или обновить, если это произойдет. Все в одном эффективном SQL-запросе.
Ответ 2
EF не подходит для вставок BULK.
Для 1000s записей это нормально, но большие числа (100k plus) медленны.
Если вы планируете использовать EF.
- попробуйте метод AddOrUpdate (вместо вставки/обновления)
- Отключить отслеживание,
- фиксировать каждые 1000 записей или меньше.
например,
Context.Set<TPoco>().AddOrUpdate(poco);
//...
Context.Configuration.AutoDetectChangesEnabled =
//..
Context.SaveChanges();
Если вы копируете несвязанные данные, вы можете попробовать эти таблицы параллельно (doh)
Ответ 3
Я сделал расширение для этого
https://efbulkinsert.codeplex.com/
и очень просто использовать
using(var context = new MyDbContext())
{
context.BulkInsert(hugeCollectionOfEntities);
}
Ответ 4
-
Создайте временную таблицу:
SqlCommand (string.Format("SELECT TOP 0 * INTO {0} FROM {1}...
-
Массовая вставка данных в него - Entity Framework Extended, упомянутый выше, должен быть изменен для поддержки имени таблицы temp, но в противном случае находится на правильном пути - или сверните немного кода и используйте SqlBulkCopy.
-
Создайте оператор MERGE.
Если вы сокрываете список свойств, вы можете сделать (2) и (3) общий. Я могу читать и объединять 150 000 строк за 20 секунд.
Ответ 5
Есть репозиторий github, который содержит оба полезных метода: BulkInsert и BulkUpdate с использованием MySql и EF6+.
BulkUpdate/BulkInsert в основном считывает все свойства из вашей общей сущности, а затем создает массовый запрос для вас.
Ps: Это было разработано для моих нужд, и проект открыт для тех, кто хочет улучшить его или изменить его на лучшее решение, которое будет полезно сообществу.
PS2: Если это не решает проблему, попробуйте внести изменения в проект, чтобы улучшить и достичь того, чего вы хотите, по крайней мере, это хорошее начало.
Пожалуйста, посмотрите на main.cs