dotnet/efcore · error · InvalidOperationException

Relational-specific methods can only be used when the…

Error message

Relational-specific methods can only be used when the context is using a relational database provider.

What it means

Thrown by RelationalDatabaseFacadeExtensions.UseTransaction(DbTransaction, Guid) when the context's transaction manager is not an IRelationalTransactionManager — meaning the context is not using a relational database provider (e.g. it is using the InMemory provider). Relational transaction APIs only work when a relational provider is registered.

Solutions

  1. Use a relational provider (UseSqlServer, UseSqlite, UseNpgsql, etc.) so the transaction manager is relational.
  2. Guard relational transaction calls behind a check of whether the provider is relational.
  3. Remove UseTransaction calls in test scenarios that run against the InMemory provider.

Example fix

// before: InMemory provider cannot accept a DbTransaction
optionsBuilder.UseInMemoryDatabase("test");
context.Database.UseTransaction(existingDbTransaction, id); // throws

// after: use a relational provider in the scenario needing transactions
optionsBuilder.UseSqlite("DataSource=:memory:");
context.Database.UseTransaction(existingDbTransaction, id);
Defensive patterns

Strategy: validation

Validate before calling

// Only enlist a DbTransaction when the provider is relational
var provider = context.Database.GetService<IRelationalConnection>();
if (provider != null)
    context.Database.UseTransaction(dbTransaction, transactionId);
else
    throw new InvalidOperationException("Context is not using a relational provider.");

Type guard

static bool IsRelational(DbContext c)
    => c.Database.GetService<IRelationalDatabaseFacadeDependencies>() != null;

Prevention

When it happens

Trigger: Calling Database.UseTransaction(dbTransaction, transactionId) on a context whose provider is non-relational (Microsoft.EntityFrameworkCore.InMemory, or a non-relational custom provider).

Common situations: Unit tests using UseInMemoryDatabase that also call UseTransaction; switching a context from SQL Server/SQLite to InMemory without removing transaction-management code; a provider that does not implement IRelationalTransactionManager.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/e26980ac87d59e50. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs:875

        => databaseFacade.UseTransaction(transaction, Guid.NewGuid());

    /// <summary>
    ///     Sets the <see cref="DbTransaction" /> to be used by database operations on the <see cref="DbContext" />.
    /// </summary>
    /// <remarks>
    ///     See <see href="https://aka.ms/efcore-docs-transactions">Transactions in EF Core</see> for more information and examples.
    /// </remarks>
    /// <param name="databaseFacade">The <see cref="DatabaseFacade" /> for the context.</param>
    /// <param name="transaction">The <see cref="DbTransaction" /> to use.</param>
    /// <param name="transactionId">The unique identifier for the transaction.</param>
    /// <returns>A <see cref="IDbContextTransaction" /> that encapsulates the given transaction.</returns>
    public static IDbContextTransaction? UseTransaction(
        this DatabaseFacade databaseFacade,
        DbTransaction? transaction,
        Guid transactionId)
        => databaseFacade.GetTransactionManager() is IRelationalTransactionManager relationalTransactionManager
            ? relationalTransactionManager.UseTransaction(transaction, transactionId)
            : throw new InvalidOperationException(RelationalStrings.RelationalNotInUse);

    /// <summary>
    ///     Sets the <see cref="DbTransaction" /> to be used by database operations on the <see cref="DbContext" />.
    /// </summary>
    /// <remarks>
    ///     See <see href="https://aka.ms/efcore-docs-transactions">Transactions in EF Core</see> for more information and examples.
    /// </remarks>
    /// <param name="databaseFacade">The <see cref="DatabaseFacade" /> for the context.</param>
    /// <param name="transaction">The <see cref="DbTransaction" /> to use.</param>
    /// <param name="cancellationToken">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
    /// <returns>A <see cref="Task" /> containing the <see cref="IDbContextTransaction" /> for the given transaction.</returns>
    /// <exception cref="OperationCanceledException">If the <see cref="CancellationToken" /> is canceled.</exception>
    public static Task<IDbContextTransaction?> UseTransactionAsync(
        this DatabaseFacade databaseFacade,
        DbTransaction? transaction,
        CancellationToken cancellationToken = default)
        => databaseFacade.UseTransactionAsync(transaction, Guid.NewGuid(), cancellationToken);

View on GitHub (pinned to 3a2006ef56)