Entity Framework Core Provider

CSharpDB.EntityFrameworkCore is an embedded-only Entity Framework Core 10 provider built on top of CSharpDB.Data. Use standard EF Core DbContext, migrations, change tracking, and LINQ patterns against local CSharpDB databases.

Scope: the provider supports file-backed databases and private in-memory databases. Provider-created file connections use a warm embedded-engine pool by default. Daemon, client, endpoint, and named shared-memory transports remain outside the provider scope.

This guide documents the provider's supported behavior, current limits, and production guidance.

Install

dotnet add package CSharpDB.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Design

Microsoft.EntityFrameworkCore.Design is recommended in the application project so dotnet ef can run design-time commands cleanly.

Basic Usage

Configure your context with UseCSharpDb(...).

using CSharpDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

public sealed class BloggingContext : DbContext
{
    private readonly string? _connectionString;

    public BloggingContext(string databasePath)
        => _connectionString = $"Data Source={databasePath}";

    public BloggingContext(DbContextOptions<BloggingContext> options)
        : base(options)
    {
    }

    public DbSet<Blog> Blogs => Set<Blog>();
    public DbSet<Post> Posts => Set<Post>();

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured && _connectionString is not null)
            optionsBuilder.UseCSharpDb(_connectionString);
    }
}

public sealed class Blog
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public List<Post> Posts { get; set; } = [];
}

public sealed class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; }
    public string Title { get; set; } = string.Empty;
    public Blog Blog { get; set; } = null!;
}

Then use EF Core as usual.

await using var db = new BloggingContext("blogging.db");
await db.Database.EnsureCreatedAsync();

db.Blogs.Add(new Blog
{
    Name = "Engineering",
    Posts = [new Post { Title = "Hello from CSharpDB EF Core" }]
});

await db.SaveChangesAsync();

var blogs = await db.Blogs
    .Include(blog => blog.Posts)
    .OrderBy(blog => blog.Name)
    .ToListAsync();

Existing Connections and In-Memory Databases

You can pass an existing CSharpDbConnection. This is required for a private :memory: database because the database lives as long as the connection stays open.

using CSharpDB.Data;
using CSharpDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

await using var connection = new CSharpDbConnection("Data Source=:memory:");
await connection.OpenAsync();

var options = new DbContextOptionsBuilder<BloggingContext>()
    .UseCSharpDb(connection)
    .Options;

await using var db = new BloggingContext(options);
                await db.Database.EnsureCreatedAsync();

Provider-created file connections enable pooling unless the connection string explicitly sets Pooling=false. EF Core can continue its normal logical open/close pattern while CSharpDB retains one warm embedded engine. Logical close rolls back unfinished transactions and clears session-scoped temporary state; CSharpDbConnection.ClearPool and ClearAllPools perform the physical close and WAL cleanup.

Explicit Transactions

SaveChanges, commit, and rollback work inside explicit EF Core transactions. CSharpDB does not implement transaction savepoints, so the provider advertises SupportsSavepoints == false and EF Core skips its automatic pre-SaveChanges savepoint.

await using var transaction = await db.Database.BeginTransactionAsync();
db.Blogs.Add(new Blog { Name = "Transactional" });
await db.SaveChangesAsync();
await transaction.CommitAsync();
Savepoint boundary: manual CreateSavepoint, RollbackToSavepoint, and ReleaseSavepoint calls throw NotSupportedException.

Supported ASP.NET Core Identity Configuration

Provider integration tests cover Identity schema v1 with integer user and role keys. Configure that exact model explicitly.

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;

public sealed class AppUser : IdentityUser<int>;

public sealed class AppIdentityContext(
    DbContextOptions<AppIdentityContext> options)
    : IdentityDbContext<AppUser, IdentityRole<int>, int>(options)
{
    protected override Version SchemaVersion => new(1, 0);
}

builder.Services.AddDbContext<AppIdentityContext>(options =>
    options.UseCSharpDb(
        builder.Configuration.GetConnectionString("CSharpDB")!));

builder.Services
    .AddIdentity<AppUser, IdentityRole<int>>()
    .AddEntityFrameworkStores<AppIdentityContext>();

The tested workflows cover the seven schema-v1 tables, users, roles, memberships, claims, external logins, tokens, persistence across reopen, cascade cleanup, concurrency stamps, transaction rollback, and cancellation.

Current limits: the default string-key IdentityDbContext<TUser>, Identity schema versions 2 and 3, passkeys, and unlisted store APIs remain unsupported. In particular, the standard string-key role-membership join is outside the provider's bounded integer-key join surface and reports CDBEF1007.

Embedded Storage Tuning

The EF Core provider can pass embedded engine tuning down into the CSharpDbConnection it creates. Use named presets and embedded open modes when you want discoverable, compile-checked settings.

using CSharpDB.Data;
using CSharpDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

var options = new DbContextOptionsBuilder<BloggingContext>()
    .UseCSharpDb(
        "Data Source=blogging.db",
        csharpdb =>
        {
            csharpdb.UseStoragePreset(CSharpDbStoragePreset.WriteOptimized);
            csharpdb.UseEmbeddedOpenMode(CSharpDbEmbeddedOpenMode.HybridIncrementalDurable);
        })
    .Options;

Use full engine options when you need exact storage composition.

using CSharpDB.Engine;
using CSharpDB.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

var directOptions = new DatabaseOptions()
    .ConfigureStorageEngine(builder => builder.UseWriteOptimizedPreset());

var options = new DbContextOptionsBuilder<BloggingContext>()
    .UseCSharpDb(
        "Data Source=blogging.db",
        csharpdb => csharpdb.UseDirectDatabaseOptions(directOptions))
    .Options;

Provider Builder Methods

  • UseDirectDatabaseOptions(DatabaseOptions)
  • UseHybridDatabaseOptions(HybridDatabaseOptions)
  • UseStoragePreset(CSharpDbStoragePreset)
  • UseEmbeddedOpenMode(CSharpDbEmbeddedOpenMode)

Explicit DirectDatabaseOptions override Storage Preset. Explicit HybridDatabaseOptions override Embedded Open Mode. When EF Core is given an existing CSharpDbConnection, provider builder tuning is validated against that connection instead of mutating it.

For the full ADO.NET and EF Core tuning surface, see ADO.NET and EF storage tuning notes.

Migrations

For file-backed databases, the normal EF Core design-time workflow is supported.

dotnet ef migrations add InitialCreate
dotnet ef database update
dotnet ef migrations script
dotnet ef migrations script --idempotent
Analyze before deployment: the separate CSharpDB.EntityFrameworkCore.Tools package can compile a restored migration chain, inspect generated provider SQL, and optionally execute the supported chain against tool-owned in-memory scratch databases. See EF Core migration chain analysis for the command and evidence boundary.

Database.Migrate() is supported for file-backed databases. EnsureCreated() is supported for file-backed and private in-memory databases. Migrations use the standard __EFMigrationsHistory table plus a simple __EFMigrationsLock row to serialize concurrent migration runs across processes. Idempotent scripts guard migration commands with history-table checks, so one script can be applied to empty, partially migrated, or current databases.

Foreign-key upgrade note: provider versions before 4.2.0 emitted create-time foreign keys inline, so the engine assigned generated constraint names. Before dropping one of those legacy constraints, query sys.foreign_keys for its stored name and use that name in a one-time migration. New 4.2.0 schemas preserve EF constraint names.
Optional relationships: EF Core's default ClientSetNull behavior is supported when at least one dependent FK property is nullable, including mixed-nullability composite keys. EF clears the nullable components before deleting a tracked principal. The generated database foreign key remains restrictive, so a dependent that is not tracked still blocks the delete. Required ClientSetNull relationships and database-side DeleteBehavior.SetNull remain unsupported.
Primary-key migration rules: named single-TEXT and composite INTEGER/TEXT logical primary keys support standalone add/drop migrations. Adding a physical single-INTEGER primary key to populated data validates non-NULL uniqueness, makes those values the physical row IDs, and atomically rebuilds ready ordinary/unique SQL, constraint-owned, and foreign-key-support indexes. Full-text, collection, and non-ready indexes reject the operation before mutation. EF drops use DROP CONSTRAINT with the exact key name. Use raw ALTER TABLE ... DROP PRIMARY KEY only for a legacy unnamed key. Dropping a primary key preserves NOT NULL; dropping a physical INTEGER key also ends its identity role. Adds reject existing nulls or duplicates without leaving key/index metadata, and drops are blocked when an inbound foreign key has no equivalent unique candidate.
Bounded column rewrites: dependency-free INTEGER to REAL changes accept values in the exactly representable ±253 range; the reverse accepts only finite, integral signed 64-bit values. TEXT columns can change among supported collations or return to default BINARY. Ready ordinary and unique SQL indexes that inherit the column collation are rebuilt atomically with the table; explicit-collation and unrelated indexes retain their roots. Row IDs are preserved, and checks plus affected uniqueness are revalidated. Key constraints, foreign keys, full-text/collection dependencies, views on the table, table-owned triggers, cross-table triggers that reference the column, and applicable validation rules remain blocked. Compound default/type/collation/nullability commands must remain in one migration transaction so a later failure restores the original table and index roots.

Exact Decimal Foundation

decimal and nullable decimal properties use provider-owned scaled INTEGER storage without an application value converter. The default is decimal(18, 2); precision must be from 1 through 18, and scale must be from 0 through precision. Configure other supported facets with HasPrecision(precision, scale).

modelBuilder.Entity<Invoice>()
    .Property(invoice => invoice.Amount)
    .HasPrecision(18, 4);

Round trips, nullable values, parameters used with one facet mapping, equality/range comparisons, ordering, and ordinary indexes remain exact. Values with excess fractional digits are rejected instead of rounded, and values outside the configured precision fail as overflow. Raw SQL sees the scaled representation: 12.3400 at scale 4 is stored as 123400.

Bounded decimal surface: decimal keys, database defaults, generated values, precision/scale-changing migrations, and computed decimal expressions—including arithmetic, numeric casts, conditionals/coalescing, and Sum/Average/Min/Max—are not yet supported. Decimal collection/subquery Contains, cross-facet parameter reuse, comparisons with application-converter decimal mappings, and model-mapped functions with decimal parameters or returns are also rejected. Unsafe query expressions fail before command dispatch with CDBEF1006. Use HasPrecision(precision, scale), not a custom decimal store type, for the provider-owned mapping.

When calling IMigrationsSqlGenerator directly with a hand-authored AddPrimaryKeyOperation, pass the target model. A low-level call with model: null does not carry enough column metadata to identify a decimal mapping.

Database-Generated RowVersion

CSharpDB supports one nonnullable byte[] property per table configured with the standard [Timestamp] attribute or fluent IsRowVersion() API.

using System.ComponentModel.DataAnnotations;

public sealed class Document
{
    public int Id { get; set; }
    public string Contents { get; set; } = string.Empty;

    [Timestamp]
    public byte[] RowVersion { get; set; } = null!;
}

The provider creates the column as BLOB ROWVERSION. The engine initializes an opaque eight-byte token at revision 1, advances it on every successful UPDATE, and returns the generated value to EF after inserts and updates. Raw SQL, trigger-issued updates, and updates that leave all other values unchanged advance the token too. EF includes the original token in update and delete predicates, so stale tracked writes throw DbUpdateConcurrencyException.

Token semantics: tokens are big-endian per-row revisions and should be treated as opaque equality values. Unlike SQL Server rowversion, they are not drawn from one database-wide monotonically increasing counter. Explicit insert or update assignments to the rowversion column are rejected. Rowversion properties cannot participate in keys, foreign keys, or indexes, and cannot define a value converter, default, or computed SQL.
Migration boundary: initial table creation through EnsureCreated, migrations, and generated scripts is supported. Standalone migrations that add rowversion to an existing table or alter a column into or out of rowversion remain explicit rejections.

LINQ Translation

The provider supports a deliberately bounded server-side LINQ surface. Basic support includes Where, ordering, Skip/Take, scalar projections, Single, Any, Count, non-decimal constant/parameter collection Contains, and simple Include queries.

String members and methods

  • string.Length
  • Parameterless ToLower(), ToLowerInvariant(), ToUpper(), and ToUpperInvariant()
  • Parameterless Trim(), TrimStart(), and TrimEnd()
  • Replace(string, string)
  • Substring(start) and Substring(start, length); the provider converts .NET's zero-based start index to CSharpDB's one-based SQL index
  • Contains(string) with ordinal semantics
  • StartsWith(string, StringComparison.Ordinal), EndsWith(string, StringComparison.Ordinal), and Contains(string, StringComparison.Ordinal) when the comparison argument is a literal
  • EF.Functions.Like(match, pattern) and EF.Functions.Like(match, pattern, escape) over one directly mapped, converter-free TEXT property

Both culture-sensitive and invariant CLR casing methods map to CSharpDB LOWER/UPPER. They therefore use invariant server semantics, not the application's CurrentCulture.

Ordinal string predicates require provider-owned, converter-free TEXT mappings. Search text may be a constant or captured parameter, including an empty string, and is treated literally: %, _, and backslash are not wildcard or escape syntax. The dedicated translations are case-sensitive and propagate SQL NULL.

EF.Functions.Like intentionally uses SQL pattern syntax: % matches zero or more UTF-16 code units and _ matches one UTF-16 code unit. The match must be one direct converter-free TEXT property, while the pattern may be a constant or captured string, including null. CSharpDB LIKE is invariant case-insensitive. The three-string overload requires a compile-time, non-null, one-UTF-16-code-unit escape literal other than %. A positive nullable LIKE predicate excludes SQL NULL; EF Core's normal null compensation makes a negated nullable predicate include NULL rows. SQLite parity covers bounded ASCII patterns; Unicode casing and supplementary-character wildcard behavior are provider-specific.

Date and time components

  • DateTime.Year, Month, Day, Hour, Minute, and Second
  • DateOnly.Year, Month, and Day
  • TimeOnly.Hour, Minute, and Second

Double-precision math

For finite REAL-mapped values, the provider translates Math.Abs(double), Math.Round(double), Math.Floor(double), Math.Ceiling(double), Math.Truncate(double), and Math.Sign(double) in predicates, projections, and ordering. Translated functions propagate SQL NULL, and Math.Round(double) uses midpoint-to-even semantics.

Scalar numeric aggregates

The supported aggregate slice covers Count, LongCount, simple and bounded-shape Any, Sum over int, double, and nullable double, Average over double and nullable double, and Min/Max over int, double, and nullable double. Filtered, empty, and all-NULL cases are cross-checked against SQLite.

Bounded direct inner and left joins

One explicit Queryable.Join or no-comparer Queryable.LeftJoin is supported between sources that normalize to direct mapped entity roots. The outer root may have an optional Where; the inner root must remain unfiltered because EF Core otherwise emits a derived-table join target that CSharpDB's current table-reference grammar does not accept. Each side must use one direct nonnullable int, long, or int/long-backed enum property backed by INTEGER with compatible provider mappings. Supported scalar or entity result projections and post-join filtering, ordering, and Skip/Take include self-joins.

LeftJoin preserves an outer row when no inner row matches. The unmatched inner entity and reference-type members materialize as null; project unmatched inner value-type members to nullable CLR types, for example PostId = (int?)post!.Id. This explicit nullable projection prevents SQL NULL from being interpreted as a value type's CLR default.

Deliberately bounded: filtered inner sources, prior ordering or row limits, source shapes that remain projected or derived after EF normalization, nullable/text/decimal/configured-converter/transformed or composite keys, and chained joins fail before command dispatch with CDBEF1007 for Join or CDBEF1008 for LeftJoin. Comparer overloads, the classic GroupJoin/SelectMany/DefaultIfEmpty left-join pattern, standalone GroupJoin or SelectMany, RightJoin, and cross-join forms remain unsupported and report CDBEF1003.

Terminal integer set operations

Exactly one terminal no-comparer Queryable.Concat, Queryable.Union, Queryable.Intersect, or Queryable.Except is supported when both branches remain direct mapped entity tables with optional filtering and each projects one compatible, converter-free INTEGER-backed int, long, or nullable equivalent. Concat preserves duplicates. The other three operators use distinct set semantics, including one SQL NULL set value where appropriate. Result order is unspecified; materialize before applying client-side ordering or transformations.

Deliberately terminal: entity, composite, constant, converted, or transformed projections; branch ordering, row limits, distinct, grouping, joins, derived/value sources, mixed or non-integer mappings, nested or chained operations, and server-side composition after the set operation are rejected before command dispatch with CDBEF1009. The comparer overloads of Union, Intersect, and Except remain unsupported and report CDBEF1003.

Distinct numeric aggregates

The supported scalar shape is an optional Where, followed by selection of one directly mapped nonnullable int column, Distinct, and Count, LongCount, Sum, Min, or Max.

Deliberately bounded: distinct Average, nullable or non-int columns, configured value converters, ordering, row limits, predicates after Distinct, intervening operators, computed or composite selectors, casts, and derived sources are rejected with CDBEF1004 before command dispatch. Nullable Distinct().Count() and Distinct().LongCount() also cannot preserve LINQ's rule that a distinct NULL is counted once because SQL COUNT(DISTINCT column) ignores NULL.

Grouped numeric aggregates

Direct single-table GroupBy supports an optional pre-filter and direct mapped Boolean, integral, enum, default-BINARY string, or nullable keys. Composite keys must use C# anonymous types or ValueTuple. Boolean key columns must contain canonical provider-written 0/1 storage. One grouped projection can contain direct keys plus bare Count/LongCount, Sum over int/double/nullable double, Average over double/nullable double, Min/Max over int/double/nullable double, and direct nonnullable-int Distinct variants for every listed aggregate except Average. Basic HAVING predicates, including aggregate IS NULL, and ordering by a directly projected key or aggregate are supported.

double, transformed, non-BINARY-collated, or configured-converter keys; aggregate value converters; element/result selector overloads; group materialization; raw group transforms; post-projection filtering, projection, distinct, limits, set, or join operations; nested grouping; predicate/CASE aggregates; casts; and broader types or shapes are rejected with CDBEF1005 before command dispatch.

String-semantics boundary: all other string-search overloads are not translated, including default culture-sensitive StartsWith(string)/EndsWith(string), the Boolean/CultureInfo forms, non-ordinal or captured StringComparison modes, and character overloads. Transformed or configured-converter LIKE match expressions, row-derived patterns, and captured, empty, multi-character, or null escapes are also rejected. They fail before command dispatch with CDBEF1001 guidance. Plain Contains(string), the three literal-StringComparison.Ordinal overloads, and the bounded EF.Functions.Like forms above are supported. Non-decimal collection Contains over constants and parameters is also supported.

DateTimeOffset components; integral, decimal, MathF, precision-argument, midpoint-mode, and transcendental math overloads; long- and float-valued Sum/Average/Min/Max variants and other unsupported aggregate variants; broader distinct and grouped aggregate shapes; broader set-operation projections, mappings, nesting, chaining, and post-set composition; composite/chained/right/cross or derived-source joins; and correlated-query shapes remain outside the supported surface.

Unsupported-expression diagnostics

Unsupported expressions retain EF Core's InvalidOperationException and add stable provider guidance before a command is dispatched. Diagnostics identify the construct without adding parameter values.

CodeMeaning
CDBEF1001Unsupported CLR method
CDBEF1002Unsupported CLR member
CDBEF1003Recognized unsupported query operator, including TakeWhile, SkipWhile, set-operation comparer overloads, Join(comparer), LeftJoin(comparer), GroupJoin, SelectMany, DefaultIfEmpty, RightJoin, or ExecuteUpdate
CDBEF1004Unsupported distinct aggregate shape
CDBEF1005Unsupported grouped aggregate shape
CDBEF1006Unsupported decimal operation outside the exact scaled-integer foundation
CDBEF1007Unsupported inner-join shape outside the bounded direct-join surface
CDBEF1008Unsupported left-join shape outside the bounded direct-join surface
CDBEF1009Unsupported set-operation shape outside the bounded terminal direct-integer surface

When client evaluation is intentional, apply selective supported filters first, then call AsEnumerable() explicitly before the unsupported portion. This makes the server/client boundary visible and avoids accidentally loading an entire table.

Supported Surface

AreaSupportedNotes
Embedded runtime providerYesNo daemon or remote transports
File-backed databasesYesPrimary supported runtime and migration mode
File connection poolingYesProvider-created connections enable pooling by default; Pooling=false remains available for an explicit physical-close lifecycle
Private :memory: runtimeYesRequires an open CSharpDbConnection
EnsureCreated()YesFile-backed and private in-memory
Database.Migrate()YesFile-backed only
dotnet ef migrations addYesUse the app project with Microsoft.EntityFrameworkCore.Design
dotnet ef database updateYesFile-backed only
dotnet ef migrations scriptYesIncludes idempotent scripts guarded by __EFMigrationsHistory
CRUD + change trackingYesIncludes affected-row concurrency checks
Explicit transactionsPartialSaveChanges, commit, and rollback are supported; savepoints are not
Database-generated rowversionPartialOne nonnullable byte[] [Timestamp]/IsRowVersion() per table; runtime and initial table creation are supported, standalone add/alter migrations are not
Integer identity propagationYesSingle-column integer primary keys
Composite primary keys and indexesYesComposite primary keys are emitted as table constraints; composite unique and non-unique indexes preserve declared column order
Standalone primary-key migrationsPartialNamed logical keys add/drop; physical INTEGER adds can rekey validated populated rows and supported relational indexes atomically; EF drops match the exact constraint name
Alternate keys and unique constraintsYesNamed create-table constraints plus standalone add/drop migrations
Foreign keysPartialNamed scalar/composite create/add/drop, primary or alternate-key targets, cascade/restrict behavior, and optional-relationship ClientSetNull; database-side SetNull is unsupported
Literal column defaultsPartialHasDefaultValue(...) values that map to INTEGER, REAL, TEXT, BLOB, or NULL; computed/default SQL expressions remain unsupported
Check constraintsPartialCreate-table and standalone add/drop migrations for deterministic row-local expressions accepted by the engine
AlterColumnPartialLiteral default/nullability changes, exact dependency-free INTEGER/REAL rewrites, and TEXT collation changes with inherited ordinary/unique SQL-index rebuilding
Exact decimal mappingPartialProvider-owned scaled INTEGER storage for precision 1–18; exact round trips, parameters, comparisons, and ordering
Bounded LINQ/query subsetPartialBasic operators plus bounded direct inner and left joins, terminal direct-integer set operations, and the string, EF.Functions.Like, temporal, finite-double math, scalar numeric aggregate, direct-column distinct aggregate, and direct single-table grouped aggregate translations listed above; unsupported methods, members, operators, set-operation shapes, aggregate shapes, and join shapes receive provider diagnostics
ASP.NET Core IdentityPartialIdentity schema v1 with IdentityUser<int> and IdentityRole<int> for the documented workflows
Supported CLR typesYesbool, integral types, enums, bounded exact decimal, double, float, string, Guid, DateTime, DateTimeOffset, DateOnly, TimeOnly, byte[]

Current Limitations

  • Provider-owned decimal mapping does not yet support keys, defaults, generated values, computed decimal expressions, or precision/scale-changing migrations.
  • Complex properties are rejected until their flattened column mappings are supported.
  • ExecuteUpdate is rejected until assignment conversions and decimal facets are supported.
  • Direct Join and no-comparer LeftJoin are limited to one nonnullable int, long, or int/long-backed enum key; filtered inner sources, derived/composite/chained joins, comparer overloads, classic GroupJoin/SelectMany/DefaultIfEmpty left joins, RightJoin, and cross joins remain unsupported.
  • Set operations are limited to one terminal Concat, Union, Intersect, or Except over compatible direct converter-free INTEGER int/long column projections; branch ordering or limits, broader projections and mappings, comparer overloads, nested/chained operations, and server composition after the operation remain unsupported.
  • Optional relationships support EF's client-side ClientSetNull; database-side DeleteBehavior.SetNull/ON DELETE SET NULL remains unsupported.
  • Schemas are unsupported in runtime and migrations.
  • Computed columns and DefaultValueSql are unsupported.
  • Rowversion is limited to one nonnullable byte[] property created with its table; standalone add/alter rowversion migrations are unsupported.
  • All other string-search overloads—including default StartsWith(string)/EndsWith(string), the Boolean/CultureInfo forms, non-ordinal or captured StringComparison modes, and character overloads—plus transformed/configured-converter LIKE matches, row-derived LIKE patterns, captured or invalid LIKE escapes, and DateTimeOffset component translation are unsupported.
  • Integral, decimal, MathF, precision-argument, midpoint-mode, and transcendental math overloads are outside the supported translation surface.
  • Long- and float-valued Sum/Average/Min/Max variants, integer Average, text Min/Max, and broader distinct/grouped aggregate types and shapes remain outside the supported surface.
  • Physical INTEGER primary-key rekeying supports ready ordinary/unique SQL, constraint-owned, and foreign-key-support indexes; full-text, collection, and non-ready indexes are rejected.
  • Named shared-memory databases (:memory:<name>) are rejected.
  • Endpoint, daemon, and non-direct transports are rejected.
  • Transaction savepoints are unsupported. The provider reports that capability accurately so ordinary explicit-transaction SaveChanges calls do not issue savepoint SQL.
  • ASP.NET Core Identity is supported only for schema v1 with integer user and role keys; default string keys, schema versions 2 and 3, passkeys, and unlisted store APIs remain unsupported.
  • TEXT/BLOB type conversions, lossy numeric conversions, numeric type changes on indexed/key/foreign-key columns, and collation changes involving key/foreign-key/full-text/collection dependencies require broader rewrite support.
  • Broad table-rebuild migration emulation is not implemented; unsupported operations fail explicitly.

DDL Surface

The migrations SQL generator currently supports CreateTable (including one BLOB ROWVERSION column, literal defaults, deterministic row-local checks, composite primary keys, alternate keys, named scalar/composite foreign keys, and column collations), DropTable, RenameTable, AddColumn, RenameColumn, DropColumn, composite CreateIndex, DropIndex, RenameIndex, standalone add/drop named check, unique, foreign-key, and bounded primary-key constraints (including populated single-INTEGER rekeying with supported relational-index rebuilding), and AlterColumn changes to literal defaults, nullability, exact numeric types, and text collations with inherited ordinary/unique SQL-index rebuilding. Standalone rowversion add/alter operations, broader primary-key rekeys, indexed numeric changes, key/FK/full-text/collection-dependent column rewrites, and nonnumeric type conversions remain explicit rejections.