BitzOrcas takes a multi-adapter persistence strategy — SqlSugar is the primary ORM, EF Core is available as an optional drop-in adapter, and Dapper serves read-only query scenarios. All three share a common IUnitOfWork contract and the same CAP Outbox for transactional event publishing.
Architecture
┌──────────────────┐ │ IUnitOfWork │ └────────┬─────────┘ ┌──────────────┼──────────────┐ ▼ ▼ ▼ SqlSugar UoW CapSqlSugar UoW EfCore UoW (query-only) (CAP Outbox) (CAP Outbox) │ │ │ ▼ ▼ ▼ SqlSugar ORM SqlSugar ORM EF Core ORM + Audit Store + CAP + Audit + CAP │ │ │ └──────────────┴──────────────┘ │ ┌──────┴──────┐ │ SQL Server │ └─────────────┘SqlSugar (Primary ORM)
BitzOrcas.Infrastructure.SqlSugar is the default persistence adapter, providing:
Trim-clean query API
SqlSugar uses a fluent query API that avoids expression-tree bloat:
// Simple queryvar notes = await db.Queryable<NoteEntity>() .Where(n => n.TenantId == tenantId) .OrderByDescending(n => n.CreatedAt) .ToListAsync();
// Paginationvar page = await db.Queryable<NoteEntity>() .Where(n => n.TenantId == tenantId) .ToPageListAsync(pageNumber, pageSize, total);Global filters (multi-tenancy)
SqlSugar applies global query filters automatically — no per-query opt-in:
// Registered once in DI — applies to every query automaticallydb.QueryFilter.AddTableFilter<TenantEntityBase>(e => e.TenantId == currentTenantId);db.QueryFilter.AddTableFilter<TenantSoftDeleteEntityBase>(e => e.IsDeleted == false);Schema initialization
Instead of migration files, SqlSugar uses CodeFirst auto-mapping via PersistenceModelRegistry:
// Entities declare their metadata via attributes[SugarTable("biz_notes")]public class NoteEntity : TenantSoftDeleteEntityBase{ [SugarColumn(Length = 200)] public string Title { get; set; }
[SugarColumn(ColumnDataType = "nvarchar(max)")] public string Content { get; set; }}Schema is initialized via --init-schema flag at startup — creates tables, indexes, and seed data in one pass.
Audit store
SqlSugar ships the production audit storage backend (SqlSugarAuditLogStore) with 7-category sharded tables:
SysAuditLog— general auditSysActivityLog— user activitySysEntityPropertyChangesLog— property change trackingSysCommunicationLog— API communicationSysExternalRequestLogRecord— outbound HTTP callsSysSpecialLog— special events
CAP Outbox integration
CapSqlSugarUnitOfWork bridges SqlSugar and CAP’s Outbox pattern — domain events and integration events are published atomically within the same database transaction:
// Events are queued in Outbox table, published by CAP after commitawait unitOfWork.PublishAsync(new NoteCreatedIntegrationEvent(noteId));await unitOfWork.CommitAsync(); // commits DB + Outbox atomicallyEF Core (Optional Adapter)
BitzOrcas.Infrastructure.EfCore provides a drop-in replacement:
- Same
IUnitOfWorkcontract - Same CAP Outbox bridge (
DotNetCore.CAP.SqlServer) - Mirrors every SqlSugar repository with an EF Core equivalent
- Set via
Persistence:Provider=EfCorein configuration
Dapper (Read-only queries)
BitzOrcas.Infrastructure.Dapper provides lightweight read-only queries for scenarios where you need maximum performance:
// Dapper for read-heavy reporting queriesconst string sql = "SELECT * FROM biz_notes WHERE TenantId = @TenantId";var notes = await connection.QueryAsync<NoteEntity>(sql, new { TenantId = tenantId });Entity hierarchy
EntityBase (snowflake Id)├── TenantEntityBase (+ TenantId, global filter)│ ├── TenantSoftDeleteEntityBase (+ IsDeleted)│ │ └── All business entities (biz_*)│ └── Identity entities (sys_*)└── BizEntityBase (business entity marker)
AuditEntityBase (separate hierarchy for sharded audit tables)├── AuditTenantEntityBase (+ TenantId)└── AuditTenantSoftDeleteEntityBase (+ IsDeleted)Configuration
{ "ConnectionStrings": { "Default": "Server=localhost;Database=BitzOrcas;User Id=sa;Password=..." }, "Persistence": { "Provider": "SqlSugar" // or "EfCore" }, "RabbitMq": { "Host": "localhost", "Port": 5672 }}Assembly reference
BitzOrcas.Infrastructure.SqlSugar ├── DependencyInjection.cs → AddBitzOrcasSqlSugarWithCap() ├── SqlSugarUnitOfWork.cs → IUnitOfWork implementation ├── Cap/ → CapSqlSugarUnitOfWork, Outbox extensions ├── Auditing/ → Audit store + entities + retention ├── Seeders/ → CsvSeedReader, CsvSeedStepBase ├── Mapping/ → PersistenceModelRegistry, SchemaInitializer └── {Module}/ → Per-module SqlSugar repositories
BitzOrcas.Infrastructure.EfCore ├── DependencyInjection.cs → AddBitzOrcasEfCoreWithCap() └── {Module}/ → Per-module EF Core repositories
BitzOrcas.Infrastructure.Dapper └── Dapper query extensions
BitzOrcas.Infrastructure.Persistence.Models ├── Entities/ → Base entity hierarchy ├── Identity/ → Sys* platform entities ├── MasterData/ → Master data entities └── {Module}/ → Per-module entities