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. It does not target daemon, client, endpoint, or pooled connection transports.

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();

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

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.

Supported Surface

AreaSupportedNotes
Embedded runtime providerYesNo daemon or remote transports
File-backed databasesYesPrimary supported runtime and migration mode
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 scriptYesNon-idempotent scripts only
CRUD + change trackingYesIncludes affected-row concurrency checks
Integer identity propagationYesSingle-column integer primary keys
Basic LINQ/query subsetYesWhere, ordering, pagination, scalar projections, First/Single, Any, Count, null checks, Contains, and simple navigation-loading joins
Supported CLR typesYesbool, integral types, enums, double, float, string, Guid, DateTime, DateTimeOffset, DateOnly, TimeOnly, byte[]

Current Limitations

  • decimal requires an explicit value converter.
  • Schemas are unsupported in runtime and migrations.
  • Defaults, computed columns, check constraints, and rowversion are unsupported.
  • Pooled connections are rejected by the EF Core provider.
  • Named shared-memory databases (:memory:<name>) are rejected.
  • Endpoint, daemon, and non-direct transports are rejected.
  • Standalone foreign-key alteration migrations are unsupported.
  • Idempotent migration scripts are unsupported in v1.
  • Broad table-rebuild migration emulation is not implemented; unsupported operations fail explicitly.

DDL Surface

The migrations SQL generator currently supports CreateTable, DropTable, RenameTable, AddColumn, RenameColumn, DropColumn, CreateIndex, and DropIndex. Foreign keys are supported only when emitted inline during CreateTable, and only for the current single-column shape supported by the engine.