/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual async Task ExecuteNonQueryAsync( IEnumerable <MigrationCommand> migrationCommands, IRelationalConnection connection, CancellationToken cancellationToken = default) { Check.NotNull(migrationCommands, nameof(migrationCommands)); Check.NotNull(connection, nameof(connection)); var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled); try { await connection.OpenAsync(cancellationToken); try { IDbContextTransaction transaction = null; try { foreach (var command in migrationCommands) { if (transaction == null && !command.TransactionSuppressed) { transaction = await connection.BeginTransactionAsync(cancellationToken); } if (transaction != null && command.TransactionSuppressed) { transaction.Commit(); await transaction.DisposeAsync(); transaction = null; } await command.ExecuteNonQueryAsync(connection, cancellationToken : cancellationToken); } transaction?.Commit(); } finally { if (transaction != null) { await transaction.DisposeAsync(); } } } finally { await connection.CloseAsync(); } } finally { await transactionScope.DisposeAsyncIfAvailable(); } }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> public virtual async ValueTask DisposeAsync() { if (!_disposed) { InterceptionResult?interceptionResult = null; try { _reader.Close(); // can throw interceptionResult = _logger?.DataReaderDisposing( _connection, _command, _reader, _commandId, _reader.RecordsAffected, _readCount, _startTime, _stopwatch.Elapsed); // can throw } finally { _disposed = true; if (interceptionResult == null) { await _reader.DisposeAsyncIfAvailable(); _command.Parameters.Clear(); await _command.DisposeAsyncIfAvailable(); await _connection.CloseAsync(); } } } }
private static async Task CleanupCommandAsync( DbCommand command, IRelationalConnection connection) { command.Parameters.Clear(); await command.DisposeAsync().ConfigureAwait(false); await connection.CloseAsync().ConfigureAwait(false); }
private static async Task CleanupCommandAsync( DbCommand command, IRelationalConnection connection) { command.Parameters.Clear(); await command.DisposeAsyncIfAvailable(); await connection.CloseAsync(); }
private static async Task CleanupCommandAsync( DbCommand command, IRelationalConnection connection, CancellationToken cancellationToken = default) { command.Parameters.Clear(); await command.DisposeAsyncIfAvailable(); await connection.CloseAsync(cancellationToken); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual async Task <int> ExecuteAsync( IEnumerable <ModificationCommandBatch> commandBatches, IRelationalConnection connection, CancellationToken cancellationToken = default) { var rowsAffected = 0; IDbContextTransaction startedTransaction = null; try { if (connection.CurrentTransaction == null && (connection as ITransactionEnlistmentManager)?.EnlistedTransaction == null && Transaction.Current == null && CurrentContext.Context.Database.AutoTransactionsEnabled) { startedTransaction = await connection.BeginTransactionAsync(cancellationToken); } else { await connection.OpenAsync(cancellationToken); } foreach (var batch in commandBatches) { await batch.ExecuteAsync(connection, cancellationToken); rowsAffected += batch.ModificationCommands.Count; } if (startedTransaction != null) { await startedTransaction.CommitAsync(cancellationToken); } } finally { if (startedTransaction != null) { await startedTransaction.DisposeAsync(); } else { await connection.CloseAsync(); } } return(rowsAffected); }
public virtual async ValueTask DisposeAsync() { if (!_disposed) { var interceptionResult = default(InterceptionResult); try { _reader.Close(); // can throw if (_logger != null) { interceptionResult = _logger.DataReaderDisposing( _connection, _command, _reader, _commandId, _reader.RecordsAffected, _readCount, _startTime, _stopwatch.Elapsed); // can throw } } finally { _disposed = true; if (!interceptionResult.IsSuppressed) { await _reader.DisposeAsync().ConfigureAwait(false); _command.Parameters.Clear(); await _command.DisposeAsync().ConfigureAwait(false); await _connection.CloseAsync().ConfigureAwait(false); } } } }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual async Task ExecuteNonQueryAsync( IEnumerable <MigrationCommand> migrationCommands, IRelationalConnection connection, CancellationToken cancellationToken = default) { var userTransaction = connection.CurrentTransaction; if (userTransaction is not null && migrationCommands.Any(x => x.TransactionSuppressed)) { throw new NotSupportedException(RelationalStrings.TransactionSuppressedMigrationInUserTransaction); } var transactionScope = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled); try { await connection.OpenAsync(cancellationToken).ConfigureAwait(false); try { IDbContextTransaction?transaction = null; try { foreach (var command in migrationCommands) { if (transaction == null && !command.TransactionSuppressed && userTransaction is null) { transaction = await connection.BeginTransactionAsync(cancellationToken) .ConfigureAwait(false); } if (transaction != null && command.TransactionSuppressed) { await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); await transaction.DisposeAsync().ConfigureAwait(false); transaction = null; } await command.ExecuteNonQueryAsync(connection, cancellationToken : cancellationToken) .ConfigureAwait(false); } if (transaction != null) { await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); } } finally { if (transaction != null) { await transaction.DisposeAsync().ConfigureAwait(false); } } } finally { await connection.CloseAsync().ConfigureAwait(false); } } finally { await transactionScope.DisposeAsyncIfAvailable().ConfigureAwait(false); } }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual async Task <int> ExecuteAsync( IEnumerable <ModificationCommandBatch> commandBatches, IRelationalConnection connection, CancellationToken cancellationToken = default) { var rowsAffected = 0; var transaction = connection.CurrentTransaction; var beganTransaction = false; var createdSavepoint = false; try { if (transaction == null && (connection as ITransactionEnlistmentManager)?.EnlistedTransaction == null && Transaction.Current == null && CurrentContext.Context.Database.AutoTransactionsEnabled) { transaction = await connection.BeginTransactionAsync(cancellationToken).ConfigureAwait(false); beganTransaction = true; } else { await connection.OpenAsync(cancellationToken).ConfigureAwait(false); if (transaction?.SupportsSavepoints == true && CurrentContext.Context.Database.AutoSavepointsEnabled) { await transaction.CreateSavepointAsync(SavepointName, cancellationToken).ConfigureAwait(false); createdSavepoint = true; } } foreach (var batch in commandBatches) { await batch.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false); rowsAffected += batch.ModificationCommands.Count; } if (beganTransaction) { await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); } } catch { if (createdSavepoint && connection.DbConnection.State == ConnectionState.Open) { try { await transaction.RollbackToSavepointAsync(SavepointName, cancellationToken).ConfigureAwait(false); } catch (Exception e) { UpdateLogger.BatchExecutorFailedToRollbackToSavepoint(CurrentContext.GetType(), e); } } throw; } finally { if (beganTransaction) { await transaction.DisposeAsync().ConfigureAwait(false); } else { if (createdSavepoint) { if (connection.DbConnection.State == ConnectionState.Open) { try { await transaction.ReleaseSavepointAsync(SavepointName, cancellationToken).ConfigureAwait(false); } catch (Exception e) { UpdateLogger.BatchExecutorFailedToReleaseSavepoint(CurrentContext.GetType(), e); } } } await connection.CloseAsync().ConfigureAwait(false); } } return(rowsAffected); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual async Task <int> ExecuteAsync( IEnumerable <ModificationCommandBatch> commandBatches, IRelationalConnection connection, CancellationToken cancellationToken = default) { var rowsAffected = 0; var transaction = connection.CurrentTransaction; var beganTransaction = false; var createdSavepoint = false; try { if (transaction == null && (connection as ITransactionEnlistmentManager)?.EnlistedTransaction == null && Transaction.Current == null && CurrentContext.Context.Database.AutoTransactionsEnabled) { transaction = await connection.BeginTransactionAsync(cancellationToken); beganTransaction = true; } else { await connection.OpenAsync(cancellationToken); if (transaction?.AreSavepointsSupported == true) { await transaction.SaveAsync(SavepointName, cancellationToken); createdSavepoint = true; } } foreach (var batch in commandBatches) { await batch.ExecuteAsync(connection, cancellationToken); rowsAffected += batch.ModificationCommands.Count; } if (beganTransaction) { await transaction.CommitAsync(cancellationToken); } } catch { if (createdSavepoint) { await transaction.RollbackAsync(SavepointName, cancellationToken); } throw; } finally { if (createdSavepoint) { await transaction.ReleaseAsync(SavepointName, cancellationToken); } else if (beganTransaction) { await transaction.DisposeAsync(); } else { await connection.CloseAsync(); } } return(rowsAffected); }