エンティティ定義パターン
このガイドでは、MBC CQRS Serverlessアプリケーションでエンティティ、DTO、および属性を定義する方法を説明します。適切なエンティティ定義により、型安全性、読み取りと書き込み操作の明確な分離、保守可能なコードが保証されます。
このガイドを使用するタイミング
以下が必要な場合に このガイドを使用してください:
- 新しいドメインエンティティ(Product、Order、Userなど)を作成する
- APIエンドポイントの入力バリデーションを定義する
- DynamoDBストレージとRDS同期用のデータ構造を設計する
- リストクエリのページネーションを実装する
このパターンが解決する問題
| 問題 | 解決策 |
|---|---|
| エンティティ属性に型安全性がない | 属性にTypeScriptインターフェースを定義する |
| 読み取りと書き込みに同じエンティティを使用すると混乱を招く | DataEntity(読み取り)とCommandEntity(書き込み)を分離する |
| エンドポイント間でバリデーションが不整合 | class-validatorデコレーター付きDTOを使用する |
| 監査フィールド(createdAt、updatedAt)が不足 | 基底クラスに標準監査フィールドを含める |
エンティティタイプの概要
フレームワークは3つの基本エンティティクラスを提供します:
| クラス | 目的 | 用途 |
|---|---|---|
DataEntity | 読み取り操作 | DynamoDB/RDSからの クエリ結果 |
CommandEntity | 書き込み操作 | DynamoDBに送信されるコマンド |
DataListEntity | ページネーションリスト | メタデータ付きのリストレスポンス |
Data Entity
ユースケース: APIクエリからデータを返す
シナリオ: APIがフロントエンドに商品情報を返す必要がある。
問題: 生のDynamoDBアイテムは型安全性がなく、キーにバージョンサフィックスが含まれる場合がある。
解決策: DataEntityを使用して、型付き属性と算出プロパティでクエリ結果をラップする。
import { DataEntity } from "@mbc-cqrs-serverless/core";
export interface ProductAttributes {
description: string;
price: number;
category: string;
inStock: boolean;
tags?: string[];
}
export class ProductDataEntity extends DataEntity {
attributes: ProductAttributes;
constructor(partial: Partial<ProductDataEntity>) {
super(partial);
Object.assign(this, partial);
}
}
DataEntity基底クラスに含まれるもの:
| プロパティ | 型 | 必須 | 説明 |
|---|---|---|---|
pk | string | はい | パーティションキー。形式: {entityType}#{tenantCode} |
sk | string | はい | ソートキー。形式: {entityType}#{entityId} — バージョンサフィックスなし(CommandEntityとの違い) |
id | string | はい | エンティティの一意識別子 |
code | string | はい | ビジネスコード |
name | string | はい | 表示名 |
version | number | はい | 楽観的ロック用のバージョン番号 |
tenantCode | string | はい | マルチテナント分離用のテナントコード |
type | string | はい | エンティティタイプ識別子 |
cpk | string | いいえ | コマンドパーティションキー — このデータアイテムを作成・更新したコマンドのPKを記録(監査証跡) |
csk | string | いいえ | コマンドソートキー — 元コマンドの正確なSK(@versionを含む)を記録(監査証跡) |
seq | number | いいえ | シーケンス番号 |
ttl | number | いいえ | DynamoDB TTL用の有効期限(秒) |
isDeleted | boolean | いいえ | 論理削除フラグ |
source | string | いいえ | イベントソース識別子(例: 'POST /api/master', 'SQS') |
requestId | string | いいえ | トレースと冪等性のための一意のリクエストID |
createdAt | Date | いいえ | エンティティが作成されたタイムスタンプ |
createdBy | string | いいえ | エンティティを作成したユーザーID |
createdIp | string | いいえ | 作成者のIPアドレス |
updatedAt | Date | いいえ | エンティティが最後に更新されたタイムスタンプ |
updatedBy | string | いいえ | エンティティを最後に更新したユーザーID |
updatedIp | string | いいえ | 最終更新者のIPアドレス |
attributes | any | いいえ | ドメイン固有データ用のカスタム属性オブジェクト |
keyゲッターはDynamoDB操作用のpkとskを持つDetailKeyオブジェクトを返します。
Command Entity
ユースケース: コマンドによるデータの作成・更 新
シナリオ: ユーザーがフォームを送信して新しい商品を作成または既存の商品を更新する。
問題: 適切なキーとバージョンでDynamoDBコマンド発行用のデータ構造が必要。
解決策: CommandEntityを使用して、CQRSコマンド処理に必要なフィールドを持つ書き込み操作を構造化する。
import { CommandEntity } from "@mbc-cqrs-serverless/core";
export interface ProductAttributes {
description: string;
price: number;
category: string;
inStock: boolean;
tags?: string[];
}
export class ProductCommandEntity extends CommandEntity {
attributes: ProductAttributes;
constructor(partial: Partial<ProductCommandEntity>) {
super();
Object.assign(this, partial);
}
}
CommandEntity基底クラスに含まれるもの:
| プロパティ | 型 | 必須 | 説明 |
|---|---|---|---|
pk | string | はい | パーティションキー。形式: {entityType}#{tenantCode} |
sk | string | はい | ソートキー。形式: {entityType}#{entityId}@{version} |
id | string | はい | エンティティの一意識別子 |
code | string | はい | ビジネスコード |
name | string | はい | 表示名 |
version | number | はい | 楽観的ロック用のバージョン番号 |
tenantCode | string | はい | マルチテナント分離用のテナントコード |
type | string | はい | エンティティタイプ識別子 |
status | string | いいえ | 処理ステータス(例: 'PENDING', 'COMPLETED', 'FAILED') |
seq | number | いいえ | シーケンス番号 |
ttl | number | いいえ | DynamoDB TTL用の有効期限(秒) |
isDeleted | boolean | いいえ | 論理削除フラグ |
source | string | いいえ | イベントソース識別子(例: 'POST /api/master', 'SQS') |
requestId | string | いいえ | トレースと冪等性のための一意のリクエストID |
createdAt | Date | いいえ | コマンドが作成されたタイムスタンプ |
createdBy | string | いいえ | コマンドを作成したユーザーID |
createdIp | string | いいえ | 作成者のIPアドレス |
updatedAt | Date | いいえ | コマンドが最後に更新されたタイムスタンプ |
updatedBy | string | いいえ | コマンドを最後に更新したユーザーID |
updatedIp | string | いいえ | 最終更新者のIPアドレス |
attributes | any | いいえ | ドメイン固有データ用のカスタム属性オブジェクト |
keyゲッターはDynamoDB操作用のpkとskを持つDetailKeyオブジェクトを返します。
CommandEntityとDataEntityの違い
CommandEntityとDataEntityの主な違いは以下の通りです:
| 観点 | CommandEntity | DataEntity |
|---|---|---|
| テーブル | コマンド(書き込み)テーブル | データ(読み取り)テーブル |
| ソートキー | バージョンサフィックス(@{version})を含む | バージョンサフィックスなし |
status | あり(処理ステータス) | いいえ |
cpk/csk | いいえ | あり(ソースコマンドを参照) |