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.
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();
CLR Type Mappings
Convention-based properties use the following canonical SQL declarations:
| CLR property type | Canonical SQL type | Notes |
|---|---|---|
bool | BOOLEAN | Bare SQL BIT is also Boolean |
byte | TINYINT | Unsigned 8-bit range |
sbyte | INTEGER | Checked conversion through the signed 32-bit declaration |
short | SMALLINT | Signed 16-bit range |
ushort | INTEGER | Checked conversion through the signed 32-bit declaration |
int | INTEGER | Signed 32-bit range |
uint | BIGINT | Checked conversion through the signed 64-bit declaration |
long | BIGINT | Signed 64-bit range |
ulong | BIGINT | Values must fit the signed 64-bit range |
| enum | Underlying integral mapping | Uses the corresponding mapping above |
float | REAL | Floating-point value |
double | DOUBLE PRECISION | Floating-point value |
decimal | DECIMAL(18,2) | HasPrecision changes precision and scale |
string | TEXT | Length/fixed-length facets select VARCHAR(n) or CHAR(n) |
Guid | UUID | Native logical UUID declaration |
DateOnly | DATE | Date without time |
TimeOnly | TIME | Optional precision selects TIME(p) |
DateTime | DATETIME2 | Optional precision selects DATETIME2(p) |
DateTimeOffset | DATETIMEOFFSET | Optional precision selects DATETIMEOFFSET(p) |
TimeSpan | INTERVAL DAY TO SECOND | Optional precision selects INTERVAL DAY TO SECOND(p) |
byte[] | BLOB | Length/fixed-length facets select VARBINARY(n) or BINARY(n) |
rowversion byte[] | ROWVERSION | Configure with [Timestamp] or IsRowVersion() |
Nullable CLR properties use the same declaration with nullable column metadata. Explicit HasColumnType(...) can select another compatible CSharpDB declaration; see the complete SQL data type reference for aliases, facets, and logical semantics.
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();
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.
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
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.
Provider CI freezes and independently replays a representative three-version Up/Down SQL corpus. The lifecycle coverage includes empty and populated databases, downgrade/re-upgrade, failed-migration rollback and recovery, database reopen, runtime CRUD, and ADO.NET inspection of rewritten columns, keys, indexes, checks, and named relationships. The corpus is plain SQL and can be executed without EF.
CDBEF2001 instead of being deferred to deployment. This includes unsupported sequence operations and invalid CSharpDB collation names.EF migration execution remains intentionally embedded/direct. The ordinary SQL ADO.NET metadata contract is separately compared across direct, HTTP, and gRPC connections; this does not imply that Database.Migrate() accepts a remote endpoint.
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.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. Its generated database foreign key remains restrictive, so an untracked dependent still blocks the delete. Database-side DeleteBehavior.SetNull is also supported when every dependent FK property is nullable; it generates ON DELETE SET NULL and applies to tracked or untracked dependents. Required ClientSetNull relationships and SetNull relationships with any nonnullable dependent property are rejected.AddForeignKeyOperation migrations can emit all immediate ReferentialAction values for both OnDelete and OnUpdate, including SetDefault and mutating update actions. A missing or NULL child default requires that column to be nullable and outside the child primary key. EF model metadata has no SET DEFAULT delete behavior or ON UPDATE setting, so those actions are not inferred from relationship conventions. When raw SQL changes a tracked principal key, clear or reload the change tracker before reading the cascaded database values.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, foreign-key-support, and complete ready full-text-owned storage. The logical full-text owner and options remain unchanged. Collection indexes, incomplete or non-ready full-text families, and other 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.INTEGER to REAL is exact across the full signed 32-bit range; BIGINT to REAL accepts only the exactly representable ±253 range. The reverse accepts finite integral values in the target's signed 32- or 64-bit range. Affected ready ordinary and unique SQL indexes are rebuilt atomically, including composite indexes. Dependency-free TEXT to BLOB encodes UTF-8, while BLOB to TEXT requires valid UTF-8. TYPE BLOB clears the old TEXT collation; BLOB-to-TEXT starts at default BINARY and then applies any requested target collation. TEXT columns can also change among supported collations, rebuilding inherited ready SQL indexes while explicit-collation and unrelated indexes retain their roots. Row IDs are preserved, and checks plus affected uniqueness are revalidated. Key constraints, foreign keys, indexed TEXT/BLOB columns, full-text/collection or non-ready dependencies, views on the table, table-owned triggers, cross-table triggers that reference the column, and applicable validation rules remain blocked. Generated Up and Down commands order default, type, collation, and nullability changes; keep each compound sequence in one migration transaction so a later failure restores the original table and index roots.Exact Decimal Foundation
decimal and nullable decimal properties no longer require an application value converter. The provider declares DECIMAL(precision,scale) and sends CLR decimal values through the exact DbValue.Decimal representation. Round trips, parameters, arithmetic, equality/range comparisons, ordering, aggregates, defaults, keys, and ordinary indexes therefore do not pass through binary floating point or a scaled surrogate integer.
modelBuilder.Entity<Invoice>()
.Property(invoice => invoice.Amount)
.HasPrecision(18, 4);
The default is decimal(18, 2). Precision must be from 1 through 18, and scale must be from 0 through precision. Values with excess fractional digits are rejected instead of rounded, and values outside the configured precision fail as overflow. Raw SQL sees the same exact decimal value. Precision/scale changes use the engine's validated transactional table rewrite and fail without publishing partial data if an existing value cannot fit the target declaration.
.HasColumnType("INTEGER") on a decimal property retains the legacy scaled-integer converter and its guarded query surface without reinterpreting existing coefficients. New and convention-based models should use HasPrecision(precision, scale), DECIMAL, or NUMERIC to select native exact decimal storage.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 ROWVERSION; the legacy BLOB ROWVERSION NOT NULL spelling remains accepted. The engine allocates an opaque eight-byte token from a persisted database-wide counter and returns it 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.
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(), andToUpperInvariant() - Parameterless
Trim(),TrimStart(), andTrimEnd() Replace(string, string)Substring(start)andSubstring(start, length); the provider converts .NET's zero-based start index to CSharpDB's one-based SQL indexContains(string)with ordinal semanticsStartsWith(string, StringComparison.Ordinal),EndsWith(string, StringComparison.Ordinal), andContains(string, StringComparison.Ordinal)when the comparison argument is a literalEF.Functions.Like(match, pattern)andEF.Functions.Like(match, pattern, escape)over one directly mapped, converter-freeTEXTproperty
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, andSecondDateOnly.Year,Month, andDayTimeOnly.Hour,Minute, andSecond
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.
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.
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.
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.
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.
| Code | Meaning |
|---|---|
CDBEF1001 | Unsupported CLR method |
CDBEF1002 | Unsupported CLR member |
CDBEF1003 | Recognized unsupported query operator, including TakeWhile, SkipWhile, set-operation comparer overloads, Join(comparer), LeftJoin(comparer), GroupJoin, SelectMany, DefaultIfEmpty, RightJoin, or ExecuteUpdate |
CDBEF1004 | Unsupported distinct aggregate shape |
CDBEF1005 | Unsupported grouped aggregate shape |
CDBEF1006 | Unsafe operation involving a legacy scaled-integer or incompatible application-converter decimal mapping |
CDBEF1007 | Unsupported inner-join shape outside the bounded direct-join surface |
CDBEF1008 | Unsupported left-join shape outside the bounded direct-join surface |
CDBEF1009 | Unsupported 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
| Area | Supported | Notes |
|---|---|---|
| Embedded runtime provider | Yes | No daemon or remote transports |
| File-backed databases | Yes | Primary supported runtime and migration mode |
| File connection pooling | Yes | Provider-created connections enable pooling by default; Pooling=false remains available for an explicit physical-close lifecycle |
Private :memory: runtime | Yes | Requires an open CSharpDbConnection |
EnsureCreated() | Yes | File-backed and private in-memory |
Database.Migrate() | Yes | File-backed only |
dotnet ef migrations add | Yes | Use the app project with Microsoft.EntityFrameworkCore.Design |
dotnet ef database update | Yes | File-backed only |
dotnet ef migrations script | Yes | Includes idempotent scripts guarded by __EFMigrationsHistory |
| CRUD + change tracking | Yes | Includes affected-row concurrency checks |
| Explicit transactions | Partial | SaveChanges, commit, and rollback are supported; savepoints are not |
| Database-generated rowversion | Partial | One nonnullable byte[] [Timestamp]/IsRowVersion() per table; runtime and initial table creation are supported, standalone add/alter migrations are not |
| Integer identity propagation | Yes | Single-column integer primary keys |
| Composite primary keys and indexes | Yes | Composite primary keys are emitted as table constraints; composite unique and non-unique indexes preserve declared column order |
| Standalone primary-key migrations | Yes (bounded) | Named logical keys add/drop; physical INTEGER adds can rekey validated populated rows, supported relational indexes, and complete ready full-text-owned storage atomically; EF drops match the exact constraint name |
| Alternate keys and unique constraints | Yes | Named create-table constraints plus standalone add/drop migrations |
| Foreign keys | Yes (bounded) | Named scalar/composite create/add/drop, primary or alternate-key targets, model-level restrictive/cascade/SetNull behavior, and the full immediate delete/update action matrix through explicit migration operations |
| Literal column defaults | Yes (bounded) | HasDefaultValue(...) values that map to a supported logical type, including exact DECIMAL; computed/default SQL expressions are intentionally unsupported |
| Check constraints | Yes (bounded) | Create-table and standalone add/drop migrations for deterministic row-local expressions accepted by the engine |
AlterColumn | Yes (bounded) | Literal default/nullability changes and validated conversions among supported logical SQL declarations; dependent structures are rebuilt only when the engine can do so safely |
| Exact decimal mapping | Yes (bounded) | Native DECIMAL(p,s) / DbValue.Decimal for precision 1–18, including exact parameters, arithmetic, comparisons, ordering, aggregates, defaults, keys, and validated facet rewrites; explicit INTEGER keeps legacy compatibility |
| Bounded LINQ/query subset | Partial | Basic 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 integer-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 Identity | Partial | Identity schema v1 with IdentityUser<int> and IdentityRole<int> for the documented workflows |
| Supported CLR types | Yes | bool, integral types, enums, bounded exact decimal, double, float, string, Guid, DateTime, DateTimeOffset, DateOnly, TimeOnly, TimeSpan, byte[] |
Current Limitations
DECIMALcolumns are not identity or rowversion storage; application-converter and explicit legacy scaled-INTEGERdecimal mappings retain a narrower query surface than nativeDECIMAL.- Complex properties are rejected until their flattened column mappings are supported.
ExecuteUpdateis rejected until assignment conversions and decimal facets are supported.- Direct
Joinand no-comparerLeftJoinare limited to one nonnullableint,long, orint/long-backed enum key; filtered inner sources, derived/composite/chained joins, comparer overloads, classicGroupJoin/SelectMany/DefaultIfEmptyleft joins,RightJoin, and cross joins remain unsupported. - Set operations are limited to one terminal
Concat,Union,Intersect, orExceptover compatible direct converter-freeINTEGERint/longcolumn 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-sideDeleteBehavior.SetNull/ON DELETE SET NULLrequires every dependent FK property to be nullable. EF relationship-model conventions cannot expressSET DEFAULTorON UPDATE; use an explicit migration operation or reviewed raw SQL for those engine-supported actions. - Schemas are unsupported in runtime and migrations.
- Computed columns and
DefaultValueSqlare 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/CultureInfoforms, non-ordinal or capturedStringComparisonmodes, and character overloads—plus transformed/configured-converterLIKEmatches, row-derivedLIKEpatterns, captured or invalidLIKEescapes, andDateTimeOffsetcomponent translation are unsupported. - Integral,
MathF, precision-argument, midpoint-mode, and transcendental math overloads are outside the supported translation surface. - Long- and float-valued
Sum/Average/Min/Maxvariants, integerAverage, textMin/Max, and broader distinct/grouped aggregate types and shapes remain outside the supported surface. - Physical
INTEGERprimary-key rekeying supports ready ordinary/unique SQL, constraint-owned, foreign-key-support, and complete ready full-text index families; collection, incomplete full-text, 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
SaveChangescalls 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.
- Indexed
TEXT/BLOBchanges, lossy or other type conversions, ordered/range REAL index access, and rewrites involving key/foreign-key/full-text/collection or non-ready dependencies require broader support. - Broad table-rebuild migration emulation is not implemented; unsupported operations fail explicitly.
DDL Surface
The migrations SQL generator currently supports CreateTable (including one 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 and complete ready full-text-owned-store rebuilding), and AlterColumn changes to literal defaults, nullability, exact numeric types with ready SQL-index rebuilding, strict dependency-free UTF-8 TEXT/BLOB types, and text collations with inherited ordinary/unique SQL-index rebuilding. The generator emits supported conversions in both Up and Down migrations. Standalone rowversion add/alter operations, broader primary-key rekeys, indexed TEXT/BLOB changes, key/FK/full-text/collection/non-ready-dependent column rewrites, and other type conversions remain explicit rejections.