データベースのテーブル構成(ベース・_deleted・_history)
プリザンターのテーブルは、CodeDefiner がカラム定義(App_Data/Definitions/Definition_Column/*.json)から作ります。業務用のテーブルはどれも ベース・_deleted・_history の 3 つ組で作られ、論理削除では _deleted へ、バージョンアップを伴う更新では _history へ行をコピーします。
- 1.5.8.1 の定義では、業務用のテーブルは 33 種類で、すべて 3 つ組です。3 つ組を持たないのは Quartz.NET 用の 11 テーブルだけで、これはクラスタリングを有効にしたときだけ作られます。
_deletedの列はベースと同じです。_historyの列は、定義のHistoryが 1 以上の列だけです。_historyの主キーは、定義のPkHistoryが付いた列とVerです。- 拡張項目を
_historyにコピーするのは Issues・Results・Depts・Groups・Users の 5 テーブルだけです。
CodeDefiner の全体の仕組みは CodeDefiner にあります。
対象バージョン
調査は 1.5.1.0 のソースで行い、このページの内容は 1.5.8.1 のソース(コミット fdcbb3f)で確かめ直しています。テーブルの数や主キーなど、1.5.8.1 で変わっている点はソースに合わせて書いています。
テーブルが作られる仕組み
CodeDefiner の _rds は、Def.TableNameCollection() で得たテーブル名ごとに ConfigureTableSet() を呼びます(TablesConfigurator.cs#L36-L79)。テーブル名はカラム定義の TableName を重複なしで集めたもので、ModelName が _Base で始まる共通定義は除かれます(Def.cs#L106-L116)。
ConfigureTableSet() の流れは次のとおりです(TablesConfigurator.cs#L151-L211)。
図を読み込み中…
NotUpdate(画面表示や計算用)、JoinTableName(他テーブルから JOIN する列)、Calc(C# で計算する列)の列と、今のスキーマバージョンで使わない列は、どのテーブルにも作られません。- 全テーブル共通の列(
_Bases)は、定義の読み込み時に各テーブルへコピーされます。レコード系の共通列(_BaseItems)はItemIdが 1 以上のテーブルにだけコピーされます(Initializer.cs#L1050-L1090)。 - 共通列の
VerはHistoryが 21 なので(_Bases_Ver.json)、共通列を持つテーブルは必ず 3 つ組になります。 - テーブルのすべての固有列に
ExcludeBaseColumnsが付いていると、共通列は作られません(TablesConfigurator.cs#L294-L322)。1.5.8.1 で該当するのは Quartz.NET のテーブルだけです。
| 共通列 | History | 物理列 |
|---|---|---|
Ver | 21 | 作る |
Comments | 100982 | 作る |
Creator | 100983 | 作る |
Updator | 100985 | 作る |
CreatedTime | 100989 | 作る |
UpdatedTime | 100990 | 作る |
VerUp | 100992 | 作らない(NotUpdate) |
Timestamp | 100993 | 作らない(NotUpdate) |
History の値は、_history に含めるかどうかの判定と、_history の列の並び順の両方に使われます。
テーブルの一覧(1.5.8.1)
業務用のテーブル(3 つ組)
| テーブル | 内容 | テーブル | 内容 |
|---|---|---|---|
| AutoNumberings | 自動採番 | Orders | 並び順 |
| BackgroundJobs | バックグラウンドジョブ | OutgoingMails | 送信メール |
| Binaries | 添付ファイル・画像 | Parameters | パラメータ |
| Dashboards | ダッシュボード(レコード系) | Passkeys | パスキー |
| Demos | デモ | Permissions | アクセス権 |
| Depts | 組織 | Registrations | ユーザー登録 |
| Extensions | 拡張機能 | ReminderSchedules | リマインダーのスケジュール |
| GroupChildren | グループの子グループ | Results | 記録テーブル(レコード系) |
| GroupMembers | グループのメンバー | ScimTokens | SCIM トークン |
| Groups | グループ | Sessions | セッション |
| Issues | 期限付きテーブル(レコード系) | Sites | サイト(レコード系) |
| Items | 全レコード共通の親 | Statuses | 状態管理 |
| Links | リンク | SysLogs | システムログ |
| LoginKeys | ログインキー | TenantQuotaUsages | テナントの使用量 |
| MailAddresses | メールアドレス | Tenants | テナント |
| McpLogs | MCP のログ | Users | ユーザー |
| Wikis | Wiki(レコード系) |
調査時点(1.5.1.0)の 28 テーブルに加えて、1.5.8.1 の定義には BackgroundJobs、McpLogs、Parameters、ScimTokens、TenantQuotaUsages があります。レコード系(ItemId が 1 以上)は Sites・Results・Issues・Wikis・Dashboards の 5 つで、どれも Items と ReferenceId で結び付きます。
Quartz.NET のテーブル
QRTZ_BLOB_TRIGGERS、QRTZ_CALENDARS、QRTZ_CRON_TRIGGERS、QRTZ_FIRED_TRIGGERS、QRTZ_JOB_DETAILS、QRTZ_LOCKS、QRTZ_PAUSED_TRIGGER_GRPS、QRTZ_SCHEDULER_STATE、QRTZ_SIMPLE_TRIGGERS、QRTZ_SIMPROP_TRIGGERS、QRTZ_TRIGGERS の 11 テーブルです。
Quartz.jsonのClustering.Enabled(既定false)がtrueのときだけ作られます(TablesConfigurator.cs#L15-L20、Quartz.json)。- 固有列の
Historyがなく、共通列も作らないので、_deletedと_historyはありません。 - PostgreSQL ではテーブル名と列名が小文字になります(
qrtz_blob_triggersなど。TablesConfigurator.cs#L22-L34)。
物理テーブルは 33 × 3 = 99 で、クラスタリングを有効にすると 110 になります。
3 つのテーブルの列の違い
| テーブル | 列 | 並び順 |
|---|---|---|
| ベース | 物理列すべて | No 順 |
_deleted | ベースと同じ | No 順 |
_history | 物理列のうち History が 1 以上 | History 順 |
1.5.8.1 の定義では、ScimTokens 以外のテーブルは物理列すべてに History が付いているので、3 つのテーブルの列の構成は同じです。
ScimTokens だけは固有列(ScimTokenId、TenantId、UserId、TokenHash、TokenPrefix、Disabled、ExpiresTime、LastUsedTime)に History が無く、ScimTokens_history には共通列の 6 列だけが作られます(ScimTokens_TokenHash.json)。一方、ScimTokensCopyToStatement は固有列も含めて _history へ INSERT する SQL を作るので(Rds.cs#L14669-L14692)、バージョンアップを伴う更新(ScimTokenModel.cs#L359-L365)が行われると、存在しない列への INSERT になります。
新しい列の定義で History を省略すると、既定値の 0 になって _history から外れます。
主キー
ベースと _deleted の主キーは、定義の Pk が付いた列です。_history の主キーは、History と PkHistory の両方が付いた列です(Indexes.cs#L190-L212)。共通列の Ver は PkHistory が 3 なので、すべての _history の主キーに入ります。
_history の主キー | テーブル |
|---|---|
固有の ID など + Ver | BackgroundJobs、Binaries、Dashboards、Depts、GroupChildren、GroupMembers、Groups、Issues、Items、MailAddresses、OutgoingMails、Parameters、Permissions、Registrations、Results、Sites、SysLogs、TenantQuotaUsages、Tenants、Users、Wikis |
Ver だけ | AutoNumberings、Demos、Extensions、Links、LoginKeys、McpLogs、Orders、Passkeys、ReminderSchedules、ScimTokens、Sessions、Statuses |
Ver だけのテーブルは、別のレコードの同じバージョンの履歴を 2 件入れられません。
Tenants_history の主キーは、1.5.8.1 の定義では TenantId に PkHistory: 1 があるので (TenantId, Ver) です(Tenants_TenantId.json)。調査時点(1.5.1.0)の定義には PkHistory が無く、主キーは (Ver) だけでした。
_deleted の主キーはベースと同じなので、同じ ID の行は 1 件しか入りません。
SQL でのテーブルの選び方
SQL を組み立てるときは、Sqls.TableTypes でベース・_deleted・_history のどれを使うかを選びます(Sqls.cs#L14-L23)。
| 値 | 対象 |
|---|---|
Normal | ベース |
Deleted | _deleted |
History / HistoryWithoutFlag | _history |
NormalAndDeleted | ベース + _deleted の UNION |
NormalAndHistory | ベース + _history の UNION |
All | 3 つの UNION |
各 SQL 文は TableBracket、HistoryTableBracket、DeletedTableBracket の 3 つのテーブル名を持っていて(SqlStatement.cs#L13-L15)、TableTypes に応じてどれかを使います。
論理削除・復元・履歴のコピー
| 操作 | SQL |
|---|---|
論理削除(Delete{テーブル}Statement) | ベースの Updator・UpdatedTime を更新 → _deleted に INSERT ... SELECT → ベースから DELETE |
復元(Restore{テーブル}Statement) | _deleted の Updator・UpdatedTime を更新 → ベースに INSERT ... SELECT → _deleted から DELETE |
履歴のコピー({テーブル}CopyToStatement) | 更新前の行を _history に INSERT ... SELECT してから Ver を 1 増やす |
論理削除と復元の SQL は Rds.cs に文字列で書かれています(Issues の例: Rds.cs#L20027、Rds.cs#L21824)。履歴のコピーはバージョンアップを伴う更新のときだけで、Tenants の例は TenantModel.cs#L979-L986 です。SQL だけで同じ操作をする例は 内部 CRUD を SQL で実現 にあります。
レコードを削除したときに動くテーブル
Issues の論理削除では、Items、Binaries、Issues の行が _deleted に移ります(IssueModel.cs#L2464-L2510)。Links の行は移らずにベースに残るので、復元の対象にも入っていません(IssueUtilities.cs#L6099-L6131)。
Links と Permissions に残った行のうち、参照先が Items にも Items_deleted にも無いものは、BackgroundService.json の DeleteUnusedRecord(既定 false)を true にすると、DeleteUnusedRecordTime(既定 03:00)に DeleteUnusedRecordChunkSize(既定 1000)件ずつ消されます(DeleteUnusedRecordTimer.cs#L56-L104、BackgroundService.json#L15-L17)。SQL は DeleteByUnusedReferenceId.sql で、Items と Items_deleted のテーブル名が直接書かれています(DeleteByUnusedReferenceId.sql(SQL Server))。
画面・API から削除・復元できないテーブル
Rds.cs には全テーブルの論理削除・復元の SQL がありますが、モデル側でそれを呼ぶのは一部のテーブルだけです。
- SysLogs は
SysLogModel.Delete()でSysLogs_deletedに移せますが(SysLogModel.cs#L2513)、復元するメソッドはありません。 - AutoNumberings、GroupChildren、GroupMembers、Links、LoginKeys、Orders、Permissions、ReminderSchedules、Sessions、Statuses は、モデル自身に削除・復元のメソッドがなく、親の操作に付随して書き換えられます。
拡張項目と _history
| 操作 | 拡張項目の列の扱い | 対象 |
|---|---|---|
| 履歴のコピー(CopyTo) | columnNames で渡された列を追加する | Issues、Results、Depts、Groups、Users だけ |
| 論理削除・復元 | DeleteParams() が ColumnUtilities.ExtendedColumns() で拡張項目の列を足す | 全テーブル |
- CopyTo で拡張項目の列を足すコードは、
Rds_CopyToStatementColums_Extended.jsonのIncludeに書かれた 5 テーブルにだけ生成されます(Rds_CopyToStatementColums_Extended.json)。たとえばTenantsCopyToStatementは引数にcolumnNamesを受け取りますが、使っていません(Rds.cs#L14860)。 - 論理削除・復元の列は
DeleteParams()で実行時に決まります(Rds.cs#L20167、ColumnUtilities.cs#L17-L25)。 - 標準の拡張項目(ClassA〜Z など)が定義されるのは Depts・Groups・Users・Issues・Results の 5 テーブルなので(Def.cs#L6494-L6534)、既定の構成ではコピー漏れは起きません。
- 商用ライセンスで使える
ExtendedColumnsSetは、TableNameに任意のテーブルを書けます(Def.cs#L6550-L6578)。5 テーブル以外に列を足すと、_historyにも列は作られますが、履歴のコピーでは値が入らずNULLになります。論理削除・復元では値は移ります。 - 拡張項目を増やしたときの SQL Server の行サイズ(1 行 8,060 バイト)の見積もりと、実 DB の現状を確かめる方法は SQL Server の行サイズの見積もりと現状診断 にあります。
標準パターンから外れている箇所
TableTypes を使わずにテーブル名を直接書いている主な箇所です。
| 箇所 | 内容 |
|---|---|
DeleteByUnusedReferenceId.sql | Items と Items_deleted を直接参照(上述) |
ItemUtilities の Items への JOIN | レコード系 5 テーブルのときだけ、TableTypes に応じて Items・Items_history・Items_deleted を選ぶ |
Indexes.cs の全文検索 | _deleted のときだけ Items_deleted・Binaries_deleted を見る。ゴミ箱と履歴の一覧の検索が LIKE になる話は 検索機能の内部実装 を参照 |
権限判定の SQL(CanRead.sql など) | ベースのテーブルだけを見る |