Beispiel #1
0
        /// <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);
        }
Beispiel #4
0
        private static async Task CleanupCommandAsync(
            DbCommand command,
            IRelationalConnection connection)
        {
            command.Parameters.Clear();
            await command.DisposeAsyncIfAvailable();

            await connection.CloseAsync();
        }
Beispiel #5
0
        private static async Task CleanupCommandAsync(
            DbCommand command,
            IRelationalConnection connection,
            CancellationToken cancellationToken = default)
        {
            command.Parameters.Clear();
            await command.DisposeAsyncIfAvailable();

            await connection.CloseAsync(cancellationToken);
        }
Beispiel #6
0
        /// <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);
        }
Beispiel #7
0
        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);
                    }
                }
            }
        }
Beispiel #8
0
        /// <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);
            }
        }
Beispiel #9
0
        /// <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);
        }