# Doris.EntityFrameworkCore **Repository Path**: ymjake/Doris.EntityFrameworkCore ## Basic Information - **Project Name**: Doris.EntityFrameworkCore - **Description**: Doris.EntityFrameworkCore.sln - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-18 - **Last Updated**: 2026-07-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # EntityFrameworkCore.Doris EntityFrameworkCore.Doris is a community Entity Framework Core provider for [Apache Doris](https://doris.apache.org/), built on top of the Doris MySQL-compatible protocol through [MySqlConnector](https://mysqlconnector.net/). The provider is intentionally OLAP-oriented. It aims to make EF Core useful for Doris table modeling, native Doris DDL, LINQ queries, and append-style writes, while rejecting relational features that do not fit Doris well. > This package is in early alpha. Expect API and translation behavior to evolve. ## Getting Started ```bash dotnet add package EntityFrameworkCore.Doris --prerelease ``` ```csharp using Microsoft.EntityFrameworkCore; await using var db = new AnalyticsContext(); var topPages = await db.PageViews .Where(v => v.EventDate >= new DateOnly(2026, 1, 1)) .GroupBy(v => v.Path) .Select(g => new { Path = g.Key, Views = g.Count() }) .OrderByDescending(x => x.Views) .Take(10) .ToListAsync(); public sealed class AnalyticsContext : DbContext { public DbSet PageViews => Set(); protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseDoris( "Server=127.0.0.1;Port=9030;Database=analytics;User ID=root;Password=;"); protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity(entity => { entity.HasKey(e => e.Id); entity.HasDuplicateKey(e => new { e.EventDate, e.Path }); entity.DistributedByHash(e => e.UserId, buckets: 16); entity.HasProperties(("replication_num", "1")); }); } } public sealed class PageView { public long Id { get; set; } public DateOnly EventDate { get; set; } public long UserId { get; set; } public string Path { get; set; } = ""; public long Views { get; set; } } ``` ## Doris Table Shape EntityFrameworkCore.Doris keeps the EF tracking key and the Doris table key separate. Use the normal EF Core key for identity/tracking, then configure the Doris table model explicitly: ```csharp modelBuilder.Entity(entity => { entity.HasKey(e => e.Id); entity.HasDuplicateKey(e => new { e.EventDate, e.UserId }); entity.HasUniqueKey(e => e.Id); entity.HasAggregateKey(e => new { e.EventDate, e.UserId }); entity.DistributedByHash(e => e.UserId, buckets: 32); entity.HasProperties( ("replication_num", "1"), ("enable_unique_key_merge_on_write", "true")); }); ``` The migration SQL generator emits Doris-native table DDL: ```sql CREATE TABLE `event_facts` ( ... ) DUPLICATE KEY(`event_date`, `user_id`) DISTRIBUTED BY HASH(`user_id`) BUCKETS 32 PROPERTIES( "replication_num" = "1" ); ``` ## Supported Types | Doris type | CLR type | | --- | --- | | `BOOLEAN` | `bool` | | `TINYINT` | `sbyte` | | `SMALLINT` | `short` | | `INT`, `INTEGER` | `int` | | `BIGINT` | `long` | | `LARGEINT` | `Int128`, `BigInteger` | | `FLOAT` | `float` | | `DOUBLE` | `double` | | `DECIMAL(p,s)` | `decimal` | | `DATE` | `DateOnly`, `DateTime` | | `DATETIME` | `DateTime` | | `CHAR`, `VARCHAR(n)`, `STRING` | `string` | Complex Doris types are not implemented yet. ## Current Status ### Supported - `UseDoris(...)` with connection strings, `MySqlConnection`, or `MySqlDataSource` - LINQ query translation inherited from the current relational/MySQL-based query pipeline, with Doris-specific SQL generation being added incrementally - `LIMIT` / `OFFSET` query pagination - `SaveChanges` for `INSERT` - Batch insert SQL generation - `EnsureDeleted()` for database-level cleanup - EF Core migrations for native Doris `CREATE TABLE` - `GenerateCreateScript()` for explicit Doris DDL generation - Doris migration history table generation - Doris table key, hash distribution, bucket count, and table properties annotations ### Explicitly Not Supported - Automatic schema creation APIs such as `EnsureCreated`, `HasTables`, and `CreateTables` - Change-tracker `UPDATE` and `DELETE` - EF Core schemas; use Doris databases instead - Foreign keys - EF unique constraints; use Doris table key configuration instead - Sequences - Generated/default/computed columns - Concurrency tokens - Navigation, owned, and complex property mapping - Idempotent migration scripts Unsupported features throw `NotSupportedException` early so the provider fails clearly instead of generating OLTP-shaped SQL for Doris. ## Doris Version Notes Older Doris builds such as `doris-4.1.1-rc01` had an upstream planner wrong-result issue for `UNION DISTINCT` with an outer `ORDER BY` plus `LIMIT/OFFSET` over wide entity projections. This was a Doris optimizer bug rather than a provider translation bug. EntityFrameworkCore.Doris does not inject a provider-specific `ROW_NUMBER()` workaround for that shape. The provider keeps the normal SQL translation path and relies on upgraded Doris builds instead of silently rewriting queries. We re-ran the original repro on `doris-4.1.3-rc02-7126cf65d96`, both through raw SQL and through the EF Core functional tests, and the query returned the correct result with the expected `ContactName` branch-local sort key in `EXPLAIN VERBOSE`. ## Migrations The first migration surface focuses on Doris-native DDL: ```bash dotnet ef migrations add InitialCreate dotnet ef database update ``` Generated `CREATE TABLE` statements include key model, distribution, bucket count, and properties when configured through the fluent API. `EnsureCreated()` is intentionally not supported. Doris schema creation is expected to go through migrations or explicit execution of `GenerateCreateScript()` output. `EnsureDeleted()` remains available as a database-level cleanup helper because it does not need to infer Doris table shape. ## Testing Normal build and unit tests: ```bash dotnet build dotnet test ``` Functional tests are skipped by default. To run them against a local Doris FE: ```bash $env:DORIS_RUN_INTEGRATION = "1" $env:DORIS_TEST_CONNECTION = "Server=127.0.0.1;Port=9030;User ID=root;Password=;" dotnet test .\test\EFCore.Doris.FunctionalTests\EFCore.Doris.FunctionalTests.csproj ``` ## Building Packages ```bash dotnet pack .\src\EFCore.Doris\EFCore.Doris.csproj -c Release -o .\artifacts\packages ``` The NuGet package id is `EntityFrameworkCore.Doris`; the assembly and root namespace remain `EFCore.Doris`.