Вставка .NET Entity Framework vs Bulk Insert

Когда я использую свой объект xxxContext и выдаю несколько добавлений в таблицу, а затем SaveChanges(), как инфраструктура сущности разрешает это для SQL? Будет ли он просто делать вставку в xxx или если есть сотни строк, достаточно ли это достаточно, чтобы выпустить команду "Массовая вставка"?

Бонусный вопрос: если он не выдаст Bulk Insert, есть ли способ заставить его так, чтобы производительность моего БД не была убита отдельными вставками? Или навалом для таблицы temp, затем сливайтесь с исходной таблицей, как Upsert?

Ответ 1

Падение любого инструмента ORM заключается в том, что он "chatty". В большинстве случаев это достаточно хорошо. Иногда это не так.

Короткий ответ - "нет".

Вот почему я все же иногда выбираю IDataReader над EF или NHibernate и т.д. И для операций объемной вставки, я отправляю xml в хранимую процедуру, и я обманывал ее, а также вставлял/обновлял или вставлял туда.

Таким образом, даже когда я использую ORM, я создаю библиотеку доменов, которая не является зависимой от EF (или NHibernate)...... поэтому у меня есть "предохранительный клапан", чтобы передать ORM в определенных ситуациях.

Ответ 2

Если ваши запросы вставки - это ANSI SQL, или вы не заботитесь о поддержке баз данных multipe с вашей кодовой базой, у вас все еще есть бэкдор для создания поставщика ADO.NET из EF и выполнения некоторых необработанных вызовов SQL

fooobar.com/questions/15128/...

Я бы сделал что-то вроде этого

private void BulkInsert(IEnumerable<Person> Persons)
{

    // use the information in the link to get your connection
    DbConnection conn = ...
    using (DbCommand cmd = conn.CreateCommand())
    {

       var sb = new StringBuilder();
       sb.Append("INSERT INTO person (firstname, lastname) VALUES ");
       var count = 0;
       foreach(var person in persons)
       {
           if (count !=0) sb.Append(",");
           sb.Append(GetInsertCommand(person, count++, cmd));
       }

       if (count > 0)
       {
           cmd.CommandText = sb.ToString();
           cmd.ExecuteNonQuery();
       }
    }



   if (sb.Length > 0)
       ExecuteNonQuery(sb.ToString());
}

private string GetInsertCommand(Person person, int count, DbCommand cmd)
{
    var firstname = "@firstname" + count.ToString();
    var lastname = "@lastname" + count.ToString();
    cmd.Parameters.Add(firstname, person.Firstname);
    cmd.Parameters.Add(lastname, person.Firstname);
    return String.Format("({0},{1})", firstname, lastname);
}

Я должен признать, что я его не тестировал, но это должен быть быстрый и грязный метод обхода EF для некоторых Bulk Inserts до тех пор, пока Массовые вставки не станут частью ядра.

Обновление

Просто быстрая идея. Вы пробовали метод... из пространства имен Migrations? Возможно, это делает объемные вставки, не смотрите на него, но стоит попробовать:

private void BatchInsert(IEnumerable<Person> persons)
{
    context.Persons.AddOrUpdate(persons);
}

Я знаю, что этот метод может быть медленным, если вы определяете столбец Key как AddOrUpdate(p => p.Firstname, persons), но я бы догадался, не указав его, это должны быть все вставки (не гарантированы)

Ответ 3

В Entity Framework есть возможность для нескольких улучшений:

Set:

yourContext.Configuration.AutoDetectChangesEnabled = false;
yourContext.Configuration.ValidateOnSaveEnabled = false;

Сделайте SaveChanges() в пакетах из 100 вставок... попробуйте с 1000 и просмотрите изменения.

Так как во всех этих вставках контекст один и тот же, вы можете перестроить свой контекстный объект каждые 1000 вставок. var yourContext = new YourContext();

Выполняя эти улучшения в процессе импорта данных, я взял его от 7 минут до 6 секунд.

Фактические цифры... не могут быть 100 o 1000 в вашем случае... попробуйте и tweek его.

Ответ 4

вы можете использовать расширение объемной вставки

использование:

using EntityFramework.BulkInsert.Extensions;

context.BulkInsert(myEntities);

с DbContext:

using (var ctx = GetContext())
{
    using (var transactionScope = new TransactionScope())
    {
        // some stuff in dbcontext    
        ctx.BulkInsert(entities);    
        ctx.SaveChanges();
        transactionScope.Complete();
    }
}

Ответ 5

Im fear EF не поддерживает массовую вставку или обновление. Как вы сказали, в настоящее время EF будет генерировать кучу команд Insert и выполнять их отдельно (но все они завернуты в одну транзакцию). Были некоторые планы по внедрению пакетной обработки, но не уверен, что в последнее время наблюдается некоторый прогресс. Надеюсь, в EF6, но я как-то сомневаюсь.

Вы можете прочитать больше в discussion.

Ответ 6

Быстрое вставка метода ASP.NET Core из репозитория.

public virtual void AddRangeFastAndCommit(IEnumerable<T> entities)
{
    MyDbContext localContext = new MyDbContext(_context.Options);
    localContext.ChangeTracker.AutoDetectChangesEnabled = false;

    foreach (var entity in entities)
    {
        localContext.Add(entity);
    }

    localContext.SaveChanges();
    localContext.Dispose();
}