关于 umbraco-repository-pattern
用于构建 Umbraco 后台仓储和数据源的技能,帮助开发者组织数据操作、可选的会话存储及协调上下文;并建议自定义 API 调用使用带 Umbraco 身份验证的生成式 OpenAPI 客户端。
主要功能
- 01仓储与数据源模式
- 02CRUD 操作结构
- 03可选会话存储
- 04基于上下文的协调
- 05OpenAPI 客户端身份验证指引
适用场景
- 01分离界面与数据访问
- 02切换底层数据源
- 03在上下文中协调数据和状态
- 04构建树形仓储
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ umbraco/ umbraco-cms-backoffice-skills --skill umbraco-repository-pattern安装后在 Claude Code 中输入/umbraco-repository-pattern确认已加载。
详细介绍
Umbraco 仓储模式
这是什么?
仓储是 Backoffice 处理数据请求和更新通知的入口,它将数据访问与各种数据源(服务器、离线数据库、存储、Signal-R)解耦。仓储提供了管理数据操作的结构化方式,将业务逻辑与直接的数据访问分离,便于维护和扩展。仓储在后台使用数据源,让使用方无需了解数据的存储位置或方式即可处理数据。
重要:API 身份验证
绝不要使用原始的 fetch() 进行自定义 API 调用。 这样会导致 401 Unauthorized 错误。
始终使用配置了 Umbraco 身份验证上下文的生成式 OpenAPI 客户端。 设置说明请参阅 umbraco-openapi-client 技能。
文档
实现前,请始终获取最新文档:
- 主要文档:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/foundation/repositories
- 使用数据:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/foundation
- 存储:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/foundation
- 基础:https://docs.umbraco.com/umbraco-cms/extend-your-project/backoffice-extensions/foundation
工作流
- 获取文档 - 对上述 URL 使用 WebFetch
- 询问问题 - 要管理哪些数据?需要哪些 CRUD 操作?数据源类型是什么?
- 生成代码 - 根据最新文档实现仓储和数据源
- 说明 - 展示创建的内容及其用法
最小示例
仓储注册
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { MyRepository } from './my-repository.js';
const repositoryManifest = {
type: 'repository',
alias: 'My.Repository',
name: 'My Repository',
api: MyRepository,
};
umbExtensionsRegistry.register(repositoryManifest);
基本仓储实现(使用 OpenAPI 客户端)
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
// Import from generated OpenAPI client (see umbraco-openapi-client skill)
import { MyExtensionService } from '../api/index.js';
export class MyRepository extends UmbControllerBase {
constructor(host: UmbControllerHost) {
super(host);
}
async getAll() {
// Use generated OpenAPI client - handles auth automatically
const response = await MyExtensionService.getAll();
return response.data;
}
async getById(id: string) {
const response = await MyExtensionService.getById({ path: { id } });
return response.data;
}
async create(data: any) {
const response = await MyExtensionService.create({ body: data });
return response.data;
}
async update(id: string, data: any) {
const response = await MyExtensionService.update({
path: { id },
body: data,
});
return response.data;
}
async delete(id: string) {
await MyExtensionService.delete({ path: { id } });
}
}
在上下文中使用仓储
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
import { MyRepository } from './my-repository.js';
export class MyContext extends UmbContextBase<MyContext> {
#repository = new MyRepository(this);
#items = new UmbArrayState([]);
readonly items = this.#items.asObservable();
async loadItems() {
const data = await this.#repository.getAll();
this.#items.setValue(data);
}
async createItem(item: any) {
const newItem = await this.#repository.create(item);
this.#items.setValue([...this.#items.getValue(), newItem]);
}
async deleteItem(id: string) {
await this.#repository.delete(id);
this.#items.setValue(
this.#items.getValue().filter(item => item.id !== id)
);
}
}
带数据源的仓储(使用 OpenAPI 客户端)
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { MyDataSource } from './my-data-source.js';
export class MyRepository extends UmbControllerBase {
#dataSource = new MyDataSource(this);
async getAll() {
return await this.#dataSource.getAll();
}
async getById(id: string) {
return await this.#dataSource.getById(id);
}
}
// Data Source - uses generated OpenAPI client
import { MyExtensionService } from '../api/index.js';
export class MyDataSource extends UmbControllerBase {
async getAll() {
// Use OpenAPI client - NEVER raw fetch()
const response = await MyExtensionService.getAll();
return response.data;
}
async getById(id: string) {
const response = await MyExtensionService.getById({ path: { id } });
return response.data;
}
}
树形仓储示例
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbTreeDataSource } from '@umbraco-cms/backoffice/tree';
export class MyTreeRepository extends UmbControllerBase {
#dataSource: UmbTreeDataSource;
constructor(host: UmbControllerHost) {
super(host);
this.#dataSource = new MyTreeDataSource(this);
}
async getRootItems() {
return await this.#dataSource.getRootItems();
}
async getChildrenOf(parentKey: string) {
return await this.#dataSource.getChildrenOf(parentKey);
}
async getAncestorsOf(key: string) {
return await this.#dataSource.getAncestorsOf(key);
}
}
核心概念
仓储:数据操作的入口,抽象数据访问
数据源:实际获取/存储数据的底层机制
存储:可选层,使用 State 对象在整个会话期间保存数据
宿主元素:必须为仓储实例化一个宿主,才能正确渲染上下文
关注点分离:
- 仓储 = 提供哪些操作
- 数据源 = 如何获取/存储数据
- 存储 = 在哪里缓存数据
- 上下文 = 由谁协调一切
优势:
- UI 与数据层松耦合
- 数据源可替换
- 更易测试和维护
- 数据访问模式一致
使用模式:
- 定义包含 CRUD 方法的仓储
- 实现负责实际 I/O 的数据源
- 在上下文中实例化仓储
- 上下文协调状态和仓储
- UI 观察上下文中的状态
就是这样!始终获取最新文档,保持示例精简,并生成完整可运行的代码。
评论
支持 Markdown