2014-09-15 2 views
2

Следующий код не работает (бросание «фатальные ошибки на reader.NextResult()»)Асинхронный SQL Bulk Copy и пакетная Выбор

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

Я думаю, проблема в том, что на reader.NextResult() текущий набор результатов освобожден из памяти, но поскольку операция асинхронного ввода использует его, он генерирует фатальную ошибку (InvalidOperationException). Есть идеи?

    var sqlQuery = new DbExtensions.SqlBuilder(); 
        foreach (var table in tableBatch) 
        { 
         sqlQuery 
          .SELECT("*") 
          .FROM("[" + table.TableName + "]"); 
        } 

        var selectCmd = sqlQuery.ToCommand(clientDb); 

        logger.Info("Executing select", batchSelectSize); 
        var reader = selectCmd.ExecuteReader(); 

        var i = 0; 
        while (reader.HasRows) 
        { 
         logger.Info("Bulk insert"); 
         var table = tableBatch.ElementAt(i); 
         var bulkCopy = new SqlBulkCopy(serverDb, SqlBulkCopyOptions.Default, tx); 
         bulkCopy.DestinationTableName = String.Format("[{0}]", table.TableName); 
         bulkCopy.EnableStreaming = table.EnableStreaming;        
         bulkCopy.WriteToServerAsync(reader); 

         i++; 

         reader.NextResult(); // fatal error occures (sometimes) 
        } 

        logger.Info("Waiting for bulk operations to complete"); 
        Task.WaitAll(); 

        logger.Info("Committing transaction"); 
        tx.Commit(); 
+0

Вы используете объекты ADO.NET одновременно. Это никогда не допускается. – usr

+0

@usr на самом деле, это не * довольно * правда; если вы включили MARS, методы async позволяют конвейерно выполнять несколько операций в одном соединении. –

+0

@MarcGravell, но разрешено ли вам начинать операции и читать результаты параллельно? Я сомневаюсь в этом. Только один поток может когда-либо обращаться к тем же объектам ADO.NET за один раз, AFAIK. – usr

ответ

2

Да, вы не сделали await результат; вы слишком скоро продвигались вперед. Это должно быть:

await bulkCopy.WriteToServerAsync(reader); 

или

await bulkCopy.WriteToServerAsync(reader).ConfigureAwait(false); 

Заметим также, что Task.WaitAll() не делает ничего полезного; вы говорите: «Теперь дождитесь завершения всех нулей этих задач».

Заметим также, что если вы собираетесь async, вы могли бы также пойти async во всем:

var reader = await selectCmd.ExecuteReaderAsync(); 
... 
await bulkCopy.WriteToServerAsync(reader); 
... 
await reader.NextResultAsync(); 

(опять же, возможно, с .ConfigureAwait(false) на каждый, при желании)

+0

у нас есть возможность сделать ASYNC для этого - ObjectReader.Create? Когда я пытаюсь WriteToServerAsync (читатель), он не будет записывать в базу данных. Любые мысли, почему это не сработает? – superachu

1

Да. Вы должны задержать NextResult, пока не убедитесь, что WriteToServerAsync закончил свою работу. Самый простой способ сделать это правильно это сделать, содержащий метод async метод и awaitWriteToServerAsync, например, так:

await bulkCopy.WriteToServerAsync(reader); 

Для получения дополнительной информации о async и await, пожалуйста, см async/await tutorials like this one from dotnetperls и/или Microsoft's own documentation.

+0

Я использую цикл while для перечисления всех наборов результатов в считывателе (пакетный выбор). – Chris

+0

А, да. Верный. Возвращаясь к предыдущему ответу ... – Jesper

Смежные вопросы