dotnet/efcore · error · NotSupportedException

A DbCommand cannot be created for a non-relational query.

Error message

A DbCommand cannot be created for a non-relational query.

What it means

CreateDbCommand throws NotSupportedException with NoDbCommand when the query's executable is not an IRelationalQueryingEnumerable. This means the IQueryable was produced by a non-relational provider (in-memory, or a third-party non-relational provider) or has been wrapped in a way that hides the relational querying enumerable. The method exists to expose the DbCommand EF would execute, so a non-relational backend has nothing to return.

Solutions

  1. Ensure the DbContext is configured with a relational provider (UseSqlServer, UseNpgsql, UseSqlite, etc.) at runtime.
  2. Switch integration tests to a real relational provider (UseSqlite with in-memory connection) so CreateDbCommand works.
  3. Guard with `query.Provider is IRelationalQueryingEnumerable` or try/catch NotSupportedException when the method is optional.

Example fix

// before
options.UseInMemoryDatabase("tests");
...
var cmd = db.Blogs.CreateDbCommand();

// after — use SQLite in-memory for relational semantics
options.UseSqlite("DataSource=:memory:");
var cmd = db.Blogs.CreateDbCommand();
Defensive patterns

Strategy: validation

Validate before calling

if (query.Provider.Execute<IEnumerable>(query.Expression) is IRelationalQueryingEnumerable)
    var cmd = query.CreateDbCommand();
else
    throw new InvalidOperationException("Query is not relational; cannot create DbCommand.");

Type guard

static bool IsRelational(IQueryable q)
    => q.Provider.Execute<IEnumerable>(q.Expression) is IRelationalQueryingEnumerable;

Try / catch

try { var cmd = query.CreateDbCommand(); }
catch (NotSupportedException ex) when (ex.Message.Contains("non-relational"))
{
    // skip DbCommand inspection in test/in-memory runs
}

Prevention

When it happens

Trigger: Calling queryable.CreateDbCommand() on a query built against DbContextOptions.UseInMemoryDatabase, a test double, or a provider that does not implement IRelationalQueryingEnumerable. Also when LINQ operators fully evaluated client-side leave no relational enumerable behind.

Common situations: Test suites using InMemory provider for speed then calling CreateDbCommand for assertion; mixing provider configurations conditionally; a provider upgrade that changed the querying-enumerable type; calling CreateDbCommand on a cached or enumerated IQueryable.

Related errors


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

Appendix: source

Thrown at src/EFCore.Relational/Extensions/RelationalQueryableExtensions.cs:44

    ///         executed the command.
    ///     </para>
    ///     <para>
    ///         Note that DbCommand is an <see cref="IDisposable" /> object. The caller is responsible for disposing the returned
    ///         command.
    ///     </para>
    ///     <para>
    ///         This is only typically supported by queries generated by Entity Framework Core.
    ///     </para>
    ///     <para>
    ///         See <see href="https://aka.ms/efcore-docs-diagnostics">Logging, events, and diagnostics</see> for more information and examples.
    ///     </para>
    /// </remarks>
    /// <param name="source">The query source.</param>
    /// <returns>The query string for debugging.</returns>
    public static DbCommand CreateDbCommand(this IQueryable source)
        => source.Provider.Execute<IEnumerable>(source.Expression) is IRelationalQueryingEnumerable queryingEnumerable
            ? queryingEnumerable.CreateDbCommand()
            : throw new NotSupportedException(RelationalStrings.NoDbCommand);

    #region FromSql

    /// <summary>
    ///     Creates a LINQ query based on a raw SQL query.
    /// </summary>
    /// <remarks>
    ///     <para>
    ///         If the database provider supports composing on the supplied SQL, you can compose on top of the raw SQL query using
    ///         LINQ operators: <c>context.Blogs.FromSqlRaw("SELECT * FROM Blogs").OrderBy(b => b.Name)</c>.
    ///     </para>
    ///     <para>
    ///         As with any API that accepts SQL it is important to parameterize any user input to protect against a SQL injection
    ///         attack. You can include parameter place holders in the SQL query string and then supply parameter values as additional
    ///         arguments. Any parameter values you supply will automatically be converted to a <see cref="DbParameter" />.
    ///     </para>
    ///     <para>
    ///         However, <b>never</b> pass a concatenated or interpolated string (<c>$""</c>) with non-validated user-provided values

View on GitHub (pinned to 3a2006ef56)