SqlBulkCopy автоматически запускает транзакцию?

Я вставляю данные через SqlBulkCopy следующим образом:

public void testBulkInsert(string connection, string table, DataTable dt)
{
    using (SqlConnection con = new SqlConnection(connection))
    {
        con.Open();

        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con))
        {
            bulkCopy.DestinationTableName = table;
            bulkCopy.WriteToServer(dt);
        }
    }
}

Будет ли это автоматически обернуто в транзакцию SQL, так что если что-то пойдет не так, на полпути через БД будет оставлено то же состояние, что и до начала массовой вставки? Или половина данных будет вставлена?

то есть. мне необходимо явно называть con.BeginTransaction

Или, если я вызываю конструктор SqlBulkCopy, который принимает строку, является ли лучший способ заставить его произойти в транзакции?

public void testBulkInsert(string connection, string table, DataTable dt)
{
    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = table;
        bulkCopy.WriteToServer(dt);
    }
}

Я нахожу docs немного неясным в этом вопросе, поскольку они изначально заявляют, что

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

но затем состояние

По умолчанию операция массового копирования является собственной транзакцией. Когда ты хотите выполнить выделенную операцию массовой копии, создать новый экземпляр SqlBulkCopy с строкой подключения или использовать существующую Объект SqlConnection без активной транзакции. В каждом сценарии, операция массового копирования создает, а затем совершает или откатывает сделка.

Так что это необходимо сделать:

public void testBulkInsert(string connection, string table, DataTable dt)
{
    using (SqlConnection con = new SqlConnection(connection))
    {
        con.Open();
        using (SqlTransaction tr = con.BeginTransaction(IsolationLevel.Serializable))
        {
            using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con, SqlBulkCopyOptions.Default, tr))
            {
                bulkCopy.DestinationTableName = table;
                bulkCopy.WriteToServer(dt);
            }
            tr.Commit();
        }
    }
}

Ответ 1

Нет здесь текст из SqlBulkCopy документации в msdn

По умолчанию операция массового копирования выполняется как изолированная операция. Операция массовой копии выполняется неконтактным способом, без возможности перевернуть его назад. Если вам нужно откат всех или части массовой копии при возникновении ошибки, вы можете использовать SqlBulkCopy управляемая транзакция, выполните операцию массовой копии в рамках существующей транзакции или Транзакция транзакции System.Transactions.

EDIT: Внимательно прочитайте документацию по ссылке, которую я вам дал:

По умолчанию операция массового копирования является собственной транзакцией. Когда ты хотите выполнить выделенную операцию массовой копии, создать новую экземпляр SqlBulkCopy с строкой соединения или использовать существующий объект SqlConnection без активной транзакции. В каждом сценарий, операция массового копирования создает, а затем совершает или свертывает вернуть транзакцию.

Это написано для транзакции внутреннего объемного копирования, которая не по умолчанию!

   using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
                       connectionString, SqlBulkCopyOptions.KeepIdentity |
                       SqlBulkCopyOptions.UseInternalTransaction))
   {
       ....
   }

Посмотрите внимательно в SqlBulkCopyOptions.UseInternalTransaction! Вы явно указываете параметр UseInternalTransaction в конструкторе класса SqlBulkCopy, чтобы явно вызвать операцию массовой копии в своей собственной транзакции, в результате чего каждая партия операции массовой копии выполнялась в отдельной транзакции. Поскольку различные партии выполняются в различные транзакции, если во время операции массовой копии происходит ошибка, все строки текущей партии будут отброшены назад, но строки из предыдущих партий останутся в базе данных.


Если вам нужно отменить всю операцию массовой копии, поскольку произошла ошибка, или если массовая копия должна выполняться как часть более крупного процесса, который может быть откат, вы можете предоставить объект SqlTransaction для SqlBulkCopy конструктор.

Внешний транзакционный случай.

            using (SqlTransaction transaction =
                       destinationConnection.BeginTransaction())
            {
                using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
                           destinationConnection, SqlBulkCopyOptions.KeepIdentity,
                           transaction))
                {
                     ....
                }
            }

Как я сказал в попрошайничестве, ответ отрицательный, вы должны использовать существующую транзакцию или транзакцию внутренней массовой копии. Прочтите файл документации, который находится в ссылке, для получения дополнительной информации.

Если вы хотите иметь транзакцию, вы должны использовать один из двух случаев, которые я написал.