XiHan.Framework.Domain
领域契约包:实体协议、值对象标记、领域事件与规约。只有接口与零依赖的组合器,没有实体基类,供定义聚合的应用与持久化子系统共同引用。
| 项 | 内容 |
|---|---|
| 包 ID | XiHan.Framework.Domain |
| 环层 | Ring 2(抽象) |
| 能力 | —(纯编译期契约,没有清单) |
| 特性入口 | — |
| 配置节 | — |
| 依赖 | XiHan.Framework.Primitives |
| AOT | 兼容 |
| 稳定性 | Stable |
概述
实体按需实现协议接口,持久化 Provider 按实体实现的接口维护对应字段:IHasCreationTime 的创建时间、IHasModificationTime 的修改时间、IHasConcurrencyStamp 的并发戳、ISoftDeletable 的删除标记、IMultiTenant 的租户。聚合根 IAggregateRoot<TKey> 用组合方式持有 DomainEventBuffer 收集领域事件,提交前由 Transaction 阶段派发。Specification<T> 把条件表示成表达式,同一条件既能在内存判定,也能交给查询提供器翻译。
本包不提供实体基类、审计基类或仓储;仓储与查询在 Persistence.Abstractions。
何时使用
定义实体、聚合、值对象与查询条件时引用它。只用持久化的应用不必单独引用:Persistence.Abstractions 与 Profiles.Standard 已传递引用本包。
安装与启用
bash
dotnet add package XiHan.Framework.Domain --prerelease当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。本包没有特性,不需要 UseFeature。
主要类型
| 类型 | 命名空间 | 说明 |
|---|---|---|
IEntity<TKey> | XiHan.Framework.Domain.Entities | 有标识的实体,成员 TKey Id { get; },TKey : notnull |
IAggregateRoot<TKey> | XiHan.Framework.Domain.Entities | 聚合根:IEntity<TKey> + IHasDomainEvents |
IHasCreationTime | XiHan.Framework.Domain.Entities | DateTimeOffset CreatedAt,新增时写入 |
IHasModificationTime | XiHan.Framework.Domain.Entities | DateTimeOffset? ModifiedAt,更新时写入 |
IHasConcurrencyStamp | XiHan.Framework.Domain.Entities | string ConcurrencyStamp,新增与更新时刷新,更新时比对 |
ISoftDeletable | XiHan.Framework.Domain.Entities | bool IsDeleted、DateTimeOffset? DeletedAt,删除改为打标 |
IMultiTenant | XiHan.Framework.Domain.Entities | string TenantId,新增时写入当前租户,查询按当前租户过滤 |
IDomainEvent | XiHan.Framework.Domain.Events | 领域事件,成员 DateTimeOffset OccurredAt(UTC) |
IHasDomainEvents | XiHan.Framework.Domain.Events | DomainEvents(尚未派发的事件)与 ClearDomainEvents() |
DomainEventBuffer | XiHan.Framework.Domain.Events | 有界事件缓冲:Add、Items、Clear,缺省容量 DefaultCapacity(256) |
IValueObject | XiHan.Framework.Domain.ValueObjects | 值对象标记,配合 record 取得值相等 |
ISpecification<T> | XiHan.Framework.Domain.Specifications | Criteria 表达式与 IsSatisfiedBy |
Specification<T> | XiHan.Framework.Domain.Specifications | 规约实现:And、Or、Not,可继承 |
Specification | XiHan.Framework.Domain.Specifications | 工厂:All<T>()(恒真,按类型缓存)、Of<T>(criteria) |
使用示例
带软删除、创建时间与领域事件的聚合:
csharp
using XiHan.Framework.Domain.Entities;
using XiHan.Framework.Domain.Events;
namespace SimpleApp.Payments;
public sealed class Payment : IAggregateRoot<Guid>, IHasCreationTime, ISoftDeletable
{
// 一笔支付的事件很少,容量给小一些也够
private readonly DomainEventBuffer _events = new(capacity: 16);
public Guid Id { get; init; }
public decimal Amount { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public bool IsDeleted { get; set; }
public DateTimeOffset? DeletedAt { get; set; }
public IReadOnlyList<IDomainEvent> DomainEvents => _events.Items;
public void Refund(DateTimeOffset now) => _events.Add(new PaymentRefunded(Id, Amount, now));
public void ClearDomainEvents() => _events.Clear();
}
public sealed record PaymentRefunded(Guid PaymentId, decimal Amount, DateTimeOffset OccurredAt) : IDomainEvent;规约的组合与内存判定:
csharp
using SimpleApp.Payments;
using XiHan.Framework.Domain.Specifications;
var large = Specification.Of<Payment>(p => p.Amount >= 1000m);
var recent = Specification.Of<Payment>(p => p.CreatedAt >= DateTimeOffset.UtcNow.AddDays(-7));
var largeOrOld = large.Or(recent.Not());
var payment = new Payment { Amount = 50m, CreatedAt = DateTimeOffset.UtcNow.AddDays(-30) };
var matched = largeOrOld.IsSatisfiedBy(payment); // true:不是近 7 天的行为与限制
DomainEventBuffer的容量小于 1 时构造抛出ArgumentOutOfRangeException;已达容量时Add抛出InvalidOperationException,不丢弃事件。缓冲不是线程安全的,聚合在一个调用里使用。Specification<T>第一次IsSatisfiedBy时编译Criteria并缓存委托;只交给查询提供器的规约不编译。And/Or把右侧表达式的参数替换为左侧参数,组合结果只有一个参数,能被 EF Core 等 LINQ 提供器翻译。- 规约里只用目标 Provider 能翻译的成员与运算;可空值类型与
null的比较在三个持久化 Provider 上都按是否有值判定。 - 接口只描述字段,不含行为:字段何时写入、怎样过滤由持久化 Provider 按 RFC-0005 执行,见持久化。
IValueObject不参与任何持久化映射。
相关
- 领域模型
- 持久化
- 工作单元与事务
- Persistence.Abstractions
- Persistence.Generators
- 规范:RFC-0005《领域协议与持久化》
