Multi-ORM Dual-Engine Architecture & Selection Matrix
In enterprise backend engineering, selecting an Object-Relational Mapper (ORM) often leads to heated debates:
- SqlSugar: Highly agile CodeFirst schema synchronization, automated table partitioning by date, and built-in snowflake sequence generation;
- Entity Framework Core (EF Core): Microsoft’s flagship ORM with strict type-safety, comprehensive LINQ translation, and powerful navigation graph tracking;
- Dapper: Minimal memory overhead, near bare-metal ADO.NET throughput, and ideal support for complex read-side reporting;
- MongoDB: The gold standard for unstructured audit event logging, operational payload archiving, and schema-less document collections.
BitzOrcas.Modern avoids false dichotomies by implementing a Multi-ORM Dual-Engine architecture within src/Framework. Through unified abstractions (IRepository<T, TId>, IUnitOfWork, and strongly typed read ports), different database adapters cooperate harmoniously within the same application.
1. Division of Responsibilities Across Four Engines
BitzOrcas defines distinct boundaries and responsibilities for each adapter:
Engine Selection Matrix & Trade-offs
| Persistence Engine | Primary Strengths | Ideal Scenario | Role in BitzOrcas |
|---|---|---|---|
| SqlSugar | - Catalog probing and sub-second column/table patching - Automated physical table partitioning by month/day - Built-in snowflake primary key generation | Teams seeking rapid feature iteration and automated schema evolution without manual migration files | Default Primary Write Engine: Powers platform capabilities (Identity, Workflow, Tickets) and business aggregate CodeFirst management. |
| EF Core | - Strict ChangeTracker lifecycle - Comprehensive Fluent API entity relationship mapping - Native Microsoft ecosystem alignment & AOT support | Teams with deep EF Core expertise requiring navigation property graphs or strict compliance mandates | Isomorphic Alternative Write Engine: Provides aggregate repositories and CAP outbox support via BitzOrcasDbContext. |
| Dapper | - Micro-ORM with near-zero allocation overhead - Full control over hand-optimized raw SQL - Ideal for multi-pool connection distribution | High-concurrency dashboards, complex multi-join analytical queries, and low-latency paginated listings | Dedicated Read Engine: Implements IReadStore ports against read-only database replicas. |
| MongoDB | - Dynamic BSON document storage - High-throughput ingestion without lock contention - Ideal for wide tables and arbitrary JSON payloads | Large-scale event tracing, audit trail snapshots, and historical webhook payloads | Audit Archiving Engine: Offloads high-volume operational events from relational tables. |
2. Isomorphic Entity Invariant
To ensure business modules can switch between SqlSugar and EF Core without rewriting domain models, BitzOrcas enforces the Isomorphic Entity Invariant:
- Unified Base Types: All domain aggregate roots inherit from
TenantAggregateRoot<TId>orEntity<TId>; - Adapter-Neutral Metadata & Fluent Parity:
- Aggregate classes declare compile-time adapter-neutral metadata (
[BitzTable],[BitzColumn]) fromBitzOrcas.Persistence.Metadata, keeping the Contracts tier 100% ORM-neutral without direct SqlSugar or EF Core package dependencies; - In persistence infrastructure, source generators automate adapter translation, while EF Core mappings can reside in dedicated
IEntityTypeConfiguration<T>classes without contaminating domain logic;
- Aggregate classes declare compile-time adapter-neutral metadata (
- Transactional Outbox Parity: Both
SqlSugarUnitOfWorkandEfCoreUnitOfWorkintegrate with DotNetCore.CAP, binding domain event dispatch atomically to underlying database commits.
3. Host Composition & Dependency Injection
Switching primary persistence engines in src/Hosts/BitzOrcas.Api requires a single configuration line:
// Option A: Use SqlSugar as primary write engine (Recommended Default)builder.Services.AddBitzOrcasSqlSugar(builder.Configuration);
// Option B: Use EF Core as primary write enginebuilder.Services.AddBitzOrcasEfCore(builder.Configuration);
// Additive: Enable Dapper for specialized read portsbuilder.Services.AddBitzOrcasDapper(builder.Configuration);4. Related Architecture Decisions & Deep Dives
- EF Core Guide: EF Core Isomorphic Mapping & Outbox Integration
- Dapper Guide: Dapper Read-Side Performance & Connection Pooling
- ADR Reference: ADR 0302: Multi-ORM Isomorphic Persistence