// This primary overload is specified on the interface itself
        //public static TResult ExecuteInDbContextScope<TDbContext, TState, TResult>(this IDbContextProvider<TDbContext> provider,
        //	AmbientScopeOption scopeOption,
        //	TState state, Func<IExecutionScope<TState>, TResult> task)
        //{
        //	return provider.ExecuteInDbContextScope(scopeOption, state, task);
        //}

        /// <summary>
        /// <para>
        /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
        /// </para>
        /// <para>
        /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
        /// </para>
        /// <para>
        /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
        /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
        /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
        /// </para>
        /// <para>
        /// If a query is executed that might perform a write operation, a transaction is started automatically.
        /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
        /// The transaction is committed once the scope ends, provided that it has not aborted.
        /// </para>
        /// <para>
        /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
        /// </para>
        /// <para>
        /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
        /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
        /// </para>
        /// </summary>
        internal static void ExecuteInDbContextScope <TDbContext, TState>(this IDbContextProvider <TDbContext> provider,
                                                                          AmbientScopeOption scopeOption,
                                                                          TState state, Action <IExecutionScope <TState> > task)
        {
            provider.ExecuteInDbContextScope(scopeOption, state, ExecuteAndReturnTrue);

            // Local function that executes the given task and returns true
            bool ExecuteAndReturnTrue(IExecutionScope <TState> executionScope)
            {
                task(executionScope);
                return(true);
            }
        }
        /// <summary>
        /// Executes the requested overload of <see cref="IDbContextProvider{TDbContext}.ExecuteInDbContextScope{TState, TResult}"/> or its async variant.
        /// </summary>
        private protected async Task <TResult> Execute <TResult>(Overload overload, IDbContextProvider <TestDbContext> provider, Func <IExecutionScope, CancellationToken, Task <TResult> > task,
                                                                 AmbientScopeOption scopeOption      = AmbientScopeOption.JoinExisting,
                                                                 CancellationToken cancellationToken = default)
        {
            switch (overload)
            {
            case Overload.Async:
                await provider.ExecuteInDbContextScopeAsync(WithoutResultWithoutCancellation(task));

                return(default);

            case Overload.AsyncResult:
                return(await provider.ExecuteInDbContextScopeAsync(WithoutCancellation(task)));

            case Overload.Sync:
                provider.ExecuteInDbContextScope(SyncWithoutResult(task));
                return(default);

            case Overload.SyncResult:
                return(provider.ExecuteInDbContextScope(Sync(task)));

            case Overload.AsyncWithScopeOption:
                await provider.ExecuteInDbContextScopeAsync(scopeOption, WithoutResultWithoutCancellation(task));

                return(default);

            case Overload.AsyncResultWithScopeOption:
                return(await provider.ExecuteInDbContextScopeAsync(scopeOption, WithoutCancellation(task)));

            case Overload.SyncWithScopeOption:
                provider.ExecuteInDbContextScope(scopeOption, SyncWithoutResult(task));
                return(default);

            case Overload.SyncResultWithScopeOption:
                return(provider.ExecuteInDbContextScope(scopeOption, Sync(task)));

            case Overload.AsyncWithCancellation:
                await provider.ExecuteInDbContextScopeAsync(cancellationToken, WithoutResult(task));

                return(default);

            case Overload.AsyncResultWithCancellation:
                return(await provider.ExecuteInDbContextScopeAsync(cancellationToken, task));

            case Overload.AsyncWithScopeOptionWithCancellation:
                await provider.ExecuteInDbContextScopeAsync(scopeOption, cancellationToken, WithoutResult(task));

                return(default);

            case Overload.AsyncResultWithScopeOptionWithCancellation:
                return(await provider.ExecuteInDbContextScopeAsync(scopeOption, cancellationToken, task));

            case Overload.AsyncWithState:
                await provider.ExecuteInDbContextScopeAsync(true, cancellationToken, WithoutResult(task));

                return(default);

            case Overload.AsyncResultWithState:
                return(await provider.ExecuteInDbContextScopeAsync(true, cancellationToken, task));

            case Overload.SyncWithState:
                provider.ExecuteInDbContextScope(true, SyncWithoutResult(task));
                return(default);

            case Overload.SyncResultWithState:
                return(provider.ExecuteInDbContextScope(true, Sync(task)));

            case Overload.AsyncWithScopeOptionWithState:
                await provider.ExecuteInDbContextScopeAsync(scopeOption, true, cancellationToken, WithoutResult(task));

                return(default);

            case Overload.AsyncResultWithScopeOptionWithState:
                return(await provider.ExecuteInDbContextScopeAsync(scopeOption, true, cancellationToken, task));

            case Overload.SyncWithScopeOptionWithState:
                provider.ExecuteInDbContextScope(scopeOption, true, SyncWithoutResult(task));
                return(default);

            case Overload.SyncResultWithScopeOptionWithState:
                return(provider.ExecuteInDbContextScope(scopeOption, true, Sync(task)));

            default:
                throw new NotImplementedException();
            }
        }
 /// <summary>
 /// <para>
 /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
 /// </para>
 /// <para>
 /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
 /// </para>
 /// <para>
 /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
 /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
 /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
 /// </para>
 /// <para>
 /// If a query is executed that might perform a write operation, a transaction is started automatically.
 /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
 /// The transaction is committed once the scope ends, provided that it has not aborted.
 /// </para>
 /// <para>
 /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
 /// </para>
 /// <para>
 /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
 /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
 /// </para>
 /// </summary>
 public static TResult ExecuteInDbContextScope <TDbContext, TState, TResult>(this IDbContextProvider <TDbContext> provider,
                                                                             TState state, Func <IExecutionScope <TState>, TResult> task)
 {
     return(provider.ExecuteInDbContextScope(provider.Options.DefaultScopeOption, state, task));
 }
 /// <summary>
 /// <para>
 /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
 /// </para>
 /// <para>
 /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
 /// </para>
 /// <para>
 /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
 /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
 /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
 /// </para>
 /// <para>
 /// If a query is executed that might perform a write operation, a transaction is started automatically.
 /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
 /// The transaction is committed once the scope ends, provided that it has not aborted.
 /// </para>
 /// <para>
 /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
 /// </para>
 /// <para>
 /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
 /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
 /// </para>
 /// </summary>
 public static void ExecuteInDbContextScope <TDbContext>(this IDbContextProvider <TDbContext> provider,
                                                         Action <IExecutionScope> task)
 {
     provider.ExecuteInDbContextScope(provider.Options.DefaultScopeOption, state: task, scope => scope.State(scope));
 }
 /// <summary>
 /// <para>
 /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
 /// </para>
 /// <para>
 /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
 /// </para>
 /// <para>
 /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
 /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
 /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
 /// </para>
 /// <para>
 /// If a query is executed that might perform a write operation, a transaction is started automatically.
 /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
 /// The transaction is committed once the scope ends, provided that it has not aborted.
 /// </para>
 /// <para>
 /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
 /// </para>
 /// <para>
 /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
 /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
 /// </para>
 /// </summary>
 public static TResult ExecuteInDbContextScope <TDbContext, TResult>(this IDbContextProvider <TDbContext> provider,
                                                                     Func <IExecutionScope, TResult> task)
 {
     return(provider.ExecuteInDbContextScope(provider.Options.DefaultScopeOption, state: task, scope => scope.State(scope)));
 }
 /// <summary>
 /// <para>
 /// Performs the given <paramref name="task"/>, with access to a new ambient <typeparamref name="TDbContext"/> accessible through <see cref="IDbContextAccessor{TDbContext}"/>.
 /// </para>
 /// <para>
 /// This is the preferred way to perform work in the scope of a <see cref="DbContext"/>. It takes care of many concerns automatically.
 /// </para>
 /// <para>
 /// The task is performed through the <see cref="DbContext"/>'s <see cref="IExecutionStrategy"/>.
 /// The <see cref="IExecutionStrategy"/> may provide behavior such as retry attempts on transient exceptions.
 /// Each attempt is provided with a fresh <see cref="DbContext"/>, with no state leakage.
 /// </para>
 /// <para>
 /// If a query is executed that might perform a write operation, a transaction is started automatically.
 /// (This comes at no additional cost, since otherwise Entity Framework starts its own transaction when saving.)
 /// The transaction is committed once the scope ends, provided that it has not aborted.
 /// </para>
 /// <para>
 /// Scopes can be nested. When a scope joins an outer scope, its work is simply performed as part of the outer scope's work, with the outer scope taking care of all the above.
 /// </para>
 /// <para>
 /// A scope aborts when an exception bubbles up from its task or when <see cref="IExecutionScope.Abort"/> is called. At the end of an aborted scope, any ongoing transaction is rolled back.
 /// Further attempts to use that <see cref="DbContext"/>, even by joined parent scopes, result in a <see cref="TransactionAbortedException"/>.
 /// </para>
 /// </summary>
 public static void ExecuteInDbContextScope <TDbContext, TState>(this IDbContextProvider <TDbContext> provider,
                                                                 TState state, Action <IExecutionScope <TState> > task)
 {
     provider.ExecuteInDbContextScope(provider.Options.DefaultScopeOption, state, task);
 }