Skip to content

Latest commit

 

History

History
75 lines (52 loc) · 3.58 KB

File metadata and controls

75 lines (52 loc) · 3.58 KB

双方向 ID 持ち合い (会社↔代表者のような相互参照)

いつ使う: 1:1 で対応する2つのレコードが 互いを参照し合う 関係。

具体例:

  • 会社 ↔ 代表者
  • 注文 ↔ 領収書
  • ユーザー ↔ 拡張プロフィール

純粋な DB 設計だけ見ると 1:1 は片方向 FK が定石ですが、CLB の LinkField / ModuleField単方向 FK 前提で動くため、両側から相手を参照したいケースでは双方向 FK にしておく方が CLB の機能を素直に活かせます。

アプリの作り

親モジュールの詳細画面 (子モジュールを内包)

会社 ↔ 代表者を例にすると: - 会社の詳細画面に **代表者が ModuleField で内包**されている (会社 → 代表者方向) - 代表者の一覧・詳細から会社を参照して戻れる (代表者 → 会社方向) - 両方の画面でお互いのフィールドが見える

支えるデータ構造

mutual_main                       mutual_sub
├── id        PK ←───────────────┤ ├── id        PK
├── name                          ├── name
└── sub_id    FK → mutual_sub.id  └── main_id    FK → mutual_main.id  ←┐
                                                                        │
        (mutual_main.sub_id) ───────────────────────────────────────────┘

両側に相手への FK 列がある。

モジュールとテーブルの対応

モジュール テーブル 役割 主な参照
MutualMain mutual_main SubSlot (ModuleFieldMutualSub, DbColumn=sub_id) で子を内包
MutualSub mutual_sub Main (LinkFieldMutualMain, DbColumn=main_id) で親を逆参照。DataOnlyFields に入れて UI には出さない

CLB ではこう作る

  • 親に ModuleField、子に LinkField を置いて両側に FK 列を持たせる
  • 親の .mod.csOnAfterInitialization新規時に子の親参照に自分のテンポラリ ID をセット:
void OnAfterInitialization()
{
    if (IsNewData)
    {
        SubSlot.ChildModule.Main.Value = this.Id.Value;
    }
}
  • 親の Submit を 1 回押すと、CLB が 片方を NULL Insert → 後追い UPDATE で実 ID を埋めることで双方向サイクルを自動解決。アプリ側コードに特別な配慮は不要

DB の前提条件

  • 双方向の FK 列のどちらか (もしくは両方) が NULL 許容であること (片方を NULL Insert するため)。NOT NULL 制約が両方に付いてると CLB の解決ロジックでも DB エラーになる

標準パターン集の対応

サイドバー データ操作/双方向ID (1:1)MutualMain + MutualSub

落とし穴

  • 「親 (Main) の Submit ボタン」だけで両方保存される。子側に Submit ボタンを置く必要なし
  • 子の Main フィールドを DataOnlyFields に入れず UI に出してしまうと、ユーザーが手動で親を選ぶ必要があるように見えて混乱しやすい

関連ドキュメント