aurelius-objects について
aurelius-objectsは、TMS Aureliusを使うDelphi開発者向けの永続化ガイドです。TObjectManagerによるエンティティ操作に加え、所有権、トランザクション、関連、並行処理の規則を説明します。
主な機能
- 01TObjectManagerによる永続化管理
- 02ID検索と条件クエリの構築
- 03エンティティの保存・更新・統合・削除
- 04エンティティと検索結果の所有権管理
- 05トランザクションとバージョン競合の処理
活用シーン
- 01ID指定または条件指定でエンティティを読み込む
- 02新規オブジェクトの保存と管理対象の変更反映
- 03双方向関連とカスケード削除の処理
- 04トランザクション内で永続化操作を行う
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tmssoftware/ skills --skill aurelius-objectsインストール後、Claude Code で/aurelius-objectsを入力して読み込まれたか確認します。
同梱ファイルreferences/objects.md
詳細
基本的な使い方
必ず TObjectManager のインスタンスを介して操作してください。すべての永続化メソッド(Save、Flush、Remove など)はマネージャーで呼び出し、SQL を直接記述しないでください。
既知の ID を読み込む場合: Manager.Find<T>(Id) を使います。すでに読み込まれている場合はキャッシュされたインスタンスを返し、そうでなければデータベースにアクセスします。
条件に一致する複数のオブジェクトを読み込む場合: Manager.Find<T>(引数なし)を使って流暢なクエリビルダーを取得し、続けて .List を呼び出します。
新しいオブジェクトを保存する場合: Manager.Save(obj) を呼び出します。マネージャーがオブジェクトの所有権を取得し、その時点から変更を追跡します。Save はすぐに INSERT を実行します。新しいオブジェクトに対して Save の後に Flush を呼び出してはいけません。Flush は、すでに管理対象となっているオブジェクトの変更を永続化するためのものです。
管理対象オブジェクトを更新する場合: プロパティを変更し、Manager.Flush(単一のオブジェクトの場合は Manager.Flush(obj))を呼び出すだけです。明示的な「update」呼び出しは不要です。
一時オブジェクト(マネージャーの外部から取得したもの)を更新する場合: Manager.Update(obj) を呼び出します。ただし、これは変更されたプロパティだけではなく、すべてのプロパティをフラッシュ時に書き込む点に注意してください。
ID が競合する場合: 同じ ID のオブジェクトがすでにキャッシュされている場合は、Update の代わりに Manager.Merge<T>(transient) を使います。既存の管理対象インスタンスにデータがコピーされます。
削除する場合: Manager.Remove(obj) を呼び出します。オブジェクトは管理対象でなければなりません(このマネージャーを通じて読み込んだか、Save/Update で登録したもの)。
重要なルール
オブジェクトのライフタイム
- 管理対象エンティティはマネージャーが所有し、マネージャーが破棄されると破棄されます。手動で解放しないでください。
- クエリがリスト(
TList<T>)を返す場合は、リストは解放しますが、その中の項目は解放しないでください。項目は引き続き管理対象です。 - プロジェクションクエリ(
ListValues)はOwnsObjects = Trueのリストを返します。リストを破棄すると項目も破棄されます。 - マネージャーの解放後もエンティティを存続させる必要がある場合は、
Freeを呼び出す前にManager.OwnsObjects := Falseを設定してください。 Saveが例外を送出した場合もマネージャーにオブジェクトを所有させたい場合は、Saveの前にManager.AddOwnership(obj)を呼び出してください。
フラッシュの粒度
- 引数なしの
Manager.Flushよりも、Manager.Flush(singleObject)を優先してください。引数なしの形式ではマネージャーのキャッシュ全体を反復処理するため、多数のオブジェクトが読み込まれている場合は遅くなることがあります。
関連付け — 常にオブジェクト参照を使う
- 関連付けプロパティには、外部キーの値そのものではなく、関連付けられたオブジェクトを割り当ててください。仮に
Invoice.CustomerIdフィールドを設定すると ORM を回避してしまい、不整合が生じます。 - 双方向の関連付けでは、両方の側を設定してください。子のプロパティに親を割り当て、さらに親のコレクションに子を追加します。
// WRONG — bypasses the ORM:
Invoice.CustomerId := 42;
// CORRECT — assign the managed object:
Invoice.Customer := Manager.Find<TCustomer>(42);
コレクションからの削除
CascadeTypeAll(孤立項目の削除なし)の場合:コレクションから項目を削除すると、その外部キーはNULLに設定されます。行は孤立した状態でデータベースに残ります。CascadeTypeAllRemoveOrphanの場合:コレクションから項目を削除すると、次回のフラッシュ時にその行が削除されます。親がなければ意味を持たない子エンティティ(請求書の明細など)には、この設定を使います。
遅延関連付けとマネージャーのライフタイム
- 遅延読み込みされる関連付けにアクセスすると、その時点で SELECT が実行されます。遅延プロパティにアクセスするときは、マネージャーがまだ有効でなければなりません。遅延関連付けにアクセスする可能性があるエンティティの参照を保持したまま、マネージャーを破棄しないでください。
マージと Update の使い分け
- 同じ ID が別のインスタンスとしてすでにキャッシュされている場合、
Updateは例外を送出します。その場合はMerge<T>を使ってください。 Merge<T>の後、返されたオブジェクトが管理対象になります。渡した一時オブジェクトは管理対象になりません。自分で解放してください。
トランザクション
BeginTransactionはマネージャーではなく、コネクションで呼び出します(Manager.Connection.BeginTransaction)。- 必ず
exceptブロックでRollbackを呼び出して再送出してください。例外を握りつぶしてはいけません。 - Aurelius はネストしたトランザクションをサポートしています。データベースに反映されるのは最も外側の
Commit/Rollbackだけです。
キャッシュされた更新と IDENTITY ID
CachedUpdates = Trueで、エンティティがデータベース生成 ID(IDENTITY/自動インクリメント)を使用する場合、ほかの SQL は遅延されますが、INSERT は直ちに実行されます。処理を続行するには生成された ID が必要なためです。
[Version] を使用した同時実行制御
- バージョン管理されたエンティティが同時に変更された場合、フラッシュ時に Aurelius は
EVersionedConcurrencyControlを発生させます。オブジェクトを更新してから操作を再試行してください。
リファレンス
すべての操作に関する完全なメソッドシグネチャ、コード例、詳細については、references/objects.md をお読みください。
リファレンスでは、TObjectManager の作成と TAureliusManager コンポーネント、メモリ管理(一時オブジェクトと永続オブジェクト、一意なインスタンス、所有権の移転)、オブジェクトの保存(単純な保存、関連付けを伴う保存、カスケード、コレクション)、更新(フラッシュ、Update、Merge、Replicate、関連付けの更新)、オブジェクトの検索(ID による検索、流れるようなクエリビルダー、関連付けを介したクエリ、イーガー/レイジーなナビゲーション)、更新の再読み込み、削除(カスケードあり/なし)、エビクト、トランザクション、同時実行制御(変更フィールドの検出、エンティティのバージョン管理)、キャッシュされた更新、バッチ/一括更新について説明しています。