入門指南
本指南示範如何導入 DomainKit,包含定義聚合、設定 DbContext、註冊服務,以及進行持久化與查詢。套件目前以 .NET 10 為目標框架。
安裝
DomainKit 分為核心與 EF Core 兩個套件:
dotnet add package CloudyWing.DomainKit
dotnet add package CloudyWing.DomainKit.EntityFrameworkCore
定義聚合
聚合根繼承 AggregateRootBase(鍵為 Guid),以審計標記介面宣告需要自動填值的欄位,IHasDisabledState 之類的狀態標記介面則只統一屬性名稱與語意。
using CloudyWing.DomainKit.Entities;
public class Customer : AggregateRootBase, IHasDisabledState,
IHasCreatedTime, IHasUpdatedTime, IHasCreator, IHasUpdater, IHasDeletedTime, IHasDeleter {
public string Name { get; private set; } = "";
public bool IsDisabled { get; private set; }
private Customer() { }
public static Customer Create(string name) {
return new Customer { Name = name };
}
}
設定 DbContext
以 IXxxDbContext 介面宣告需要的資料集,在 OnModelCreating 套用審計欄位設定,並在 ConfigureConventions 套用 DomainKit 全域 convention。時間的實際儲存型別由宿主依 provider 選擇 converter。
using CloudyWing.DomainKit.EntityFrameworkCore.Modeling;
using Microsoft.EntityFrameworkCore;
public interface ICustomerDbContext {
DbSet<Customer> Customers { get; }
}
public sealed class AppDbContext : DbContext, ICustomerDbContext {
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Customer> Customers => Set<Customer>();
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) {
base.ConfigureConventions(configurationBuilder);
configurationBuilder.ApplyDomainKitConventions(new UtcDateTimeOffsetConverter());
}
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Customer>(builder => {
builder.ToTable("Customers");
builder.ConfigureFullAuditedEntity();
});
}
}
UtcDateTimeOffsetConverter 將值正規化為 offset 0。未傳入 converter 時,DomainKit 不會改變 EF Core 的預設 DateTimeOffset 對映。
註冊服務
不啟用 Outbox 時,可使用一般 AddDbContext 註冊:
services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
services.AddDomainKit<AppDbContext>(
handlerAssemblies: [typeof(Program).Assembly]
);
AddDomainKit 註冊 IUnitOfWork、審計與事件攔截器、RowVersion 攔截器、事件 dispatcher,以及行程內廣播服務。
啟用 Outbox 時,DbContext model 必須呼叫 ConfigureOutbox,DI 必須提供 IDbContextFactory<AppDbContext>,並在選項開啟背景 dispatcher。
services.AddDbContextFactory<AppDbContext>(
options => options.UseSqlServer(connectionString),
ServiceLifetime.Scoped
);
services.AddDomainKit<AppDbContext>(
options => options.EnableOutboxDispatcher = true,
handlerAssemblies: [typeof(Program).Assembly]
);
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.ConfigureOutbox();
modelBuilder.Entity<Customer>(builder => {
builder.ToTable("Customers");
builder.ConfigureFullAuditedEntity();
});
}
加入設定後建立 EF Core migration,將 OutboxMessages 與 ProcessedEvents 納入資料庫。
持久化
Repository 操作聚合,IUnitOfWork 統一提交:
Customer customer = Customer.Create("Acme");
await repository.CreateAsync(customer, cancellationToken: ct).ConfigureAwait(false);
await unitOfWork.SaveChangesAsync(actorId, ct).ConfigureAwait(false);
提交時傳入的 actorId 會作為審計使用者,未傳時退回 IAuditUser.UserId。詳見聚合與審計。
查詢
IReadOnlyList<CustomerListItem> items = await queryService.GetListAsync(
customer => new CustomerListItem(customer.Id, customer.Name),
customer => !customer.IsDisabled,
query => query.OrderBy(customer => customer.Name),
ct
).ConfigureAwait(false);
更多查詢與規約用法見查詢與規約。