public TResult ExecuteComplex <TResult>(Action <DbCommand> initializer, Func <DbDataReader, TResult> materializer)
        {
            if (unbufferedReader != null)
            {
                unbufferedReader.Buffer();
                unbufferedReader = null;
            }

            var result     = default(object);
            var connection = CurrentDbContext.Context.Database.GetService <IRelationalConnection>();

            connection.Open();

            using (var command = CreateCommand(connection))
            {
                initializer(command);

                var commandId = Guid.NewGuid();
                var startTime = DateTimeOffset.UtcNow;
                var stopwatch = Stopwatch.StartNew();

                logger.CommandExecuting(
                    command,
                    DbCommandMethod.ExecuteReader,
                    commandId,
                    connection.ConnectionId,
                    false,
                    startTime);

                try
                {
                    using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
                    {
                        logger.CommandExecuted(
                            command,
                            DbCommandMethod.ExecuteReader,
                            commandId,
                            connection.ConnectionId,
                            result,
                            false,
                            startTime,
                            stopwatch.Elapsed);

                        reader.Read();

                        CurrentDbContext.GetDependencies().StateManager.BeginTrackingQuery();

                        return(materializer(reader));
                    }
                }
                catch (Exception exception)
                {
                    logger.CommandError(
                        command,
                        DbCommandMethod.ExecuteReader,
                        commandId,
                        connection.ConnectionId,
                        exception,
                        false,
                        startTime,
                        stopwatch.Elapsed);

                    throw;
                }
                finally
                {
                    connection.Close();
                }
            }
        }
        /// <summary>
        ///    The method called by other methods on this type to execute synchronously.
        /// </summary>
        /// <param name="connection"> The connection to use. </param>
        /// <param name="executeMethod"> The method type. </param>
        /// <param name="parameterValues"> The parameter values. </param>
        /// <param name="logger"> The command logger. </param>
        /// <param name="cancellationToken"> The cancellation token. </param>
        /// <returns> The result of the execution. </returns>
        protected virtual async Task <object> ExecuteAsync(
            [NotNull] IRelationalConnection connection,
            DbCommandMethod executeMethod,
            [CanBeNull] IReadOnlyDictionary <string, object> parameterValues,
            [CanBeNull] IDiagnosticsLogger <DbLoggerCategory.Database.Command> logger,
            CancellationToken cancellationToken = default)
        {
            Check.NotNull(connection, nameof(connection));

            var dbCommand = CreateCommand(connection, parameterValues);

            await connection.OpenAsync(cancellationToken);

            var commandId = Guid.NewGuid();

            var startTime = DateTimeOffset.UtcNow;
            var stopwatch = Stopwatch.StartNew();

            logger?.CommandExecuting(
                dbCommand,
                executeMethod,
                commandId,
                connection.ConnectionId,
                async: true,
                startTime: startTime);

            object result;
            var    readerOpen = false;

            try
            {
                switch (executeMethod)
                {
                case DbCommandMethod.ExecuteNonQuery:
                {
                    result = await dbCommand.ExecuteNonQueryAsync(cancellationToken);

                    break;
                }

                case DbCommandMethod.ExecuteScalar:
                {
                    result = await dbCommand.ExecuteScalarAsync(cancellationToken);

                    break;
                }

                case DbCommandMethod.ExecuteReader:
                {
                    result = new RelationalDataReader(
                        connection,
                        dbCommand,
                        await dbCommand.ExecuteReaderAsync(cancellationToken),
                        commandId,
                        logger);
                    readerOpen = true;

                    break;
                }

                default:
                {
                    throw new NotSupportedException();
                }
                }

                logger?.CommandExecuted(
                    dbCommand,
                    executeMethod,
                    commandId,
                    connection.ConnectionId,
                    result,
                    true,
                    startTime,
                    stopwatch.Elapsed);
            }
            catch (Exception exception)
            {
                logger?.CommandError(
                    dbCommand,
                    executeMethod,
                    commandId,
                    connection.ConnectionId,
                    exception,
                    true,
                    startTime,
                    stopwatch.Elapsed);

                throw;
            }
            finally
            {
                if (!readerOpen)
                {
                    dbCommand.Parameters.Clear();
                    dbCommand.Dispose();
                    connection.Close();
                }
            }

            return(result);
        }