XiHan Framework 处于预览阶段

查看获取方式
跳转到内容

XiHan.Framework.Persistence.InMemory ​

persistence.relational@1 的内存默认实现:每种实体一张有界的表,工作单元用覆盖层实现读己之写。只用于开发、原型与测试,没有显式 Provider 时被选中。

项内容
包 IDXiHan.Framework.Persistence.InMemory
环层Ring 3(实现)
能力提供 persistence.relational@1(role: default);依赖 kernel.hosting@1
特性入口InMemoryPersistenceFeature
配置节XiHan:Persistence:InMemory
依赖XiHan.Framework.Persistence.Abstractions
AOT兼容
稳定性Preview

概述 ​

存储 InMemoryStore 是进程内单例,按实体类型各有一张 InMemoryTable<TEntity, TKey>,容量有上限。工作单元 InMemoryUnitOfWork 是作用域服务:仓储的新增、更新、删除先写进它的覆盖层,同一工作单元里的查找与查询把覆盖层叠在表的快照上,所以能读到自己的写入。表与覆盖层只存副本,读取只交出副本。提交时给涉及的表依次加锁,校验通过后应用本工作单元的变更,跨表原子;回滚只丢弃覆盖层。

创建时间、修改时间、租户、并发戳与软删除按 PersistenceConventions 执行,语义与 EF Core、SqlSugar Provider 一致,三者通过同一套一致性用例。特性同时注册 IIdGenerator<Guid>(GuidV7IdGenerator)、Transaction 阶段的 UnitOfWorkMiddleware 与持久化消息目录。

何时使用 ​

  • 本地开发、原型、演示,以及单元测试与集成测试(如 Testing.TestHost)。
  • 需要零外部依赖地跑通整条管道时;Profiles.Standard 缺省装配它。

生产环境改用 Persistence.EntityFrameworkCore 或 Persistence.SqlSugar:再 UseFeature 一个显式 Provider,内存实现即被顶替,不装配、不启动。

安装与启用 ​

bash
dotnet add package XiHan.Framework.Persistence.InMemory --prerelease

当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。Profiles.Standard 已包含本包,UseStandardProfile() 即装配;单独使用时:

csharp
using XiHan.Framework.Persistence.Abstractions.Repositories;
using XiHan.Framework.Persistence.InMemory;

builder.Services.AddRepository<Order, Guid>();
builder.AddXiHan(x => x.UseFeature<InMemoryPersistenceFeature>());

配置 ​

键类型缺省说明
XiHan:Persistence:InMemory:MaxEntitiesPerType正整数100000每种实体的容量上限(含已软删除的行);只接受纯数字,非法值启动时抛出 ArgumentException
json
{
  "XiHan": {
    "Persistence": {
      "InMemory": {
        "MaxEntitiesPerType": 10000
      }
    }
  }
}

主要类型 ​

类型说明
InMemoryPersistenceFeature特性入口;常量 HealthName 为 persistence.inmemory.capacity
InMemoryPersistenceOptions选项:MaxEntitiesPerType;FromConfiguration(configuration)
InMemoryStore单例存储;Table<TEntity, TKey>() 取表,Clear() 清空全部表,同时是健康项贡献者
InMemoryTable<TEntity, TKey>一种实体的有界表:Find、Snapshot(交出副本)、Count、Capacity
InMemoryUnitOfWork作用域工作单元,带覆盖层
InMemoryRepository<TEntity, TKey>仓储实现,由特性按登记注册

应用代码只通过 IRepository<TEntity, TKey> 与 IUnitOfWork 使用它们;InMemoryStore.Clear() 可在测试之间重置数据。

使用示例 ​

测试里清空存储,保证用例之间互不影响:

csharp
using Microsoft.Extensions.DependencyInjection;
using XiHan.Framework.Persistence.InMemory;

// host 是测试启动的宿主;存储是单例,清空后所有作用域都看到空表
host.Services.GetRequiredService<InMemoryStore>().Clear();

仓储的读写与其他 Provider 完全相同,见持久化。

行为与限制 ​

  • 容量:新增使某张表超过 MaxEntitiesPerType 时,提交返回 PERSISTENCE_UNAVAILABLE_002,该表的整批变更都不写入;覆盖已有行不占容量。
  • 读写都复制:查找、FindManyAsync、查询交出的是副本,新增、更新存的是调用方实例的副本。在读出的实例上的修改,不经 UpdateAsync 写回就不会落库,其他调用看不到,回滚后也不留痕迹。仓储写入的修改时间、并发戳与删除标记同样只进覆盖层。
  • 副本是字段逐一的浅复制:标量与协议字段互不影响;集合、嵌套对象等引用类型字段(含聚合的领域事件缓冲)仍与表里的版本共享,不在隔离范围内,不要在读出的实体上原地改集合来期待它不影响别处。
  • 提交时校验:覆盖层记下每个写过的标识首次读到的已提交状态。提交时按建表先后给涉及的表依次加锁,在全部锁内逐表校验,任一失败所有表都不改,工作单元记为回滚:
    • 两个工作单元并发新增同一标识,后提交的返回 PERSISTENCE_CONFLICT_002。
    • 更新或删除期间,别的工作单元已删掉那一行,或改过带并发戳的那一行,后提交的返回 PERSISTENCE_CONFLICT_001,不会把先提交的更新盖掉或把删掉的行写回来。
    • 不带并发戳的实体只校验行还在。
  • 更新沿用当前行的创建时间、租户与删除标记;软删除在当前行的副本上打标(调用方实例上的其他改动不写入),删除标记再同步回调用方实例。
  • 没有数据库事务,HasTransaction 与关系型 Provider 同义(ADR-0109):可写工作单元里仓储第一次接受写入调用(单条,或集合非空的批量,不论结果)起为真,覆盖层从此可能有未提交、随回滚丢弃的变更;提交(含提交时校验失败)与回滚后为假,只读工作单元恒为假。
  • 只读工作单元(只读操作或 UnitOfWorkOptions(IsReadOnly: true)):写入在进覆盖层之前就返回 PERSISTENCE_UNEXPECTED_001(批量逐项都是它,空集合仍返回空列表),并把工作单元记为失败,提交回滚并返回同一错误。
  • 进程退出数据即丢失;多个进程之间不共享。
  • 健康项 persistence.inmemory.capacity:任一张表达到容量即 Degraded(PERSISTENCE_UNAVAILABLE_002,报告按实体名排序的第一个满表),否则 Ready。
  • 命名连接(ADR-0084)不支持:内存实现没有连接。实体登记到命名连接在装配时抛出携带 PERSISTENCE_UNAVAILABLE_008 的 FrameworkException,UnitOfWorkOptions(Connection: …) 在 BeginAsync 抛出同码异常,不静默落在唯一的存储上。
  • 实体目录(ADR-0078):表名取实体类型名,列取有公开 setter 的非集合属性、列名即属性名;库结构读取不支持,返回 PERSISTENCE_UNAVAILABLE_008。
  • 运行时数据源(ADR-0078)不支持:内存实现没有数据库。注册表 DataSourceRegistry 照样登记,取用与测试连接返回 PERSISTENCE_UNAVAILABLE_008。
错误码何时出现
PERSISTENCE_CONFLICT_002新增的标识已在表或覆盖层里(含已软删除、其他租户);提交时发现新增的标识已被别的工作单元提交
PERSISTENCE_CONFLICT_001更新的游离实例并发戳与当前值不同;提交时发现更新或删除的行已被别的工作单元删除或改过
PERSISTENCE_NOTFOUND_001更新或删除的实体不存在或不可见
PERSISTENCE_VALIDATION_001多租户实体没有当前租户
PERSISTENCE_VALIDATION_002工作单元状态不允许(抛异常)
PERSISTENCE_UNEXPECTED_001只读工作单元里新增、更新、删除;提交时返回写入阶段被拒的同一错误
PERSISTENCE_UNAVAILABLE_002表已满(提交结果与健康项)
PERSISTENCE_UNAVAILABLE_008运行时数据源与库结构读取:内存实现不支持

相关 ​

Released under The MIT License