dotnet/efcore · error · InvalidOperationException
Relational-specific methods can only be used when the contex
Error message
Relational-specific methods can only be used when the context is using a relational database provider.
What it means
Thrown by DatabaseFacade.UseTransaction(DbTransaction, Guid) when the context's transaction manager is not an IRelationalTransactionManager, i.e. the context is using a non-relational provider (e.g. in-memory or Cosmos). Relational transaction APIs only work with relational providers.
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 dbf9771522)
Solutions
- Use a relational provider (SqlServer, Sqlite, etc.) when transaction sharing is required.
- Guard the call with databaseFacade.IsRelational() before invoking UseTransaction.
- In tests, replace transaction-sharing logic with a relational test database or skip it for in-memory.
- Ensure the correct UseSqlServer/UseSqlite call is active in OnConfiguring for the environment.
Example fix
// before
db.Database.UseTransaction(existingDbTransaction); // throws in tests
// after
if (db.Database.IsRelational())
await db.Database.UseTransactionAsync(existingDbTransaction); Defensive patterns
Strategy: type-guard
Validate before calling
if (db.Database.IsRelational())
db.Database.UseTransaction(transaction, transactionId); Type guard
static bool CanShareTransaction(DatabaseFacade f) => f.IsRelational();
Prevention
- Always guard relational APIs with IsRelational().
- Use a relational provider in integration tests that exercise transaction sharing.
- Centralize transaction handling in a provider-aware helper.
When it happens
Trigger: Calling UseTransaction with an ambient DbTransaction on a context backed by a non-relational provider (RelationalDatabaseFacadeExtensions.cs:873-875). The cast to IRelationalTransactionManager fails, so RelationalNotInUse is thrown.
Common situations: Using the in-memory provider in tests while code paths call UseTransaction; switching provider config at runtime; Cosmos DB provider used with relational transaction sharing code; environment-specific provider selection (Test vs Prod) where tests use in-memory.
Related errors
- User transaction is not supported with a TransactionSuppress
- User transaction is not supported with a TransactionSuppress
- The current migration SQL generator '{sqlGeneratorType}' is
- Unable to find provider assembly '{assemblyName}'. Ensure th
- Unable to find expected assembly attribute [DesignTimeProvid
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/e26980ac87d59e50.
Report an issue: GitHub.