コンテンツにスキップ

Schema と Foreign Key

AkkaraDB::Schema は型付きテーブルをまとめ、参照に関する動作を設定します。専用の制約エンジンではなく、高レベル API の調整用 helper です。

auto schema = db->schema()
.table<&Author::id>("authors")
.table<&Post::id>("posts")
.open();
auto& authors = schema.table<Author>();
auto& posts = schema.table<Post>();

schema は C++ の entity type ごとに table holder を保持します。また、登録済みテーブル間で Ref<T> field を解決するための binding も提供します。

auto schema = db->schema()
.table<&Author::id>("authors")
.table<&Post::id>("posts")
.foreignKey<&Post::author>({akkaradb::OnDelete::Cascade}, {akkaradb::OnUpdate::Cascade})
.open();

foreignKey<&Post::author>() の field は akkaradb::Ref<T> である必要があります。参照先テーブルも同じ schema に登録されている必要があります。

schema.foreignKey<&PlainPost::authorId, &Author::id>(
{akkaradb::OnDelete::Restrict},
{akkaradb::OnUpdate::Cascade}
);

source field と target field は比較可能である必要があります。target field に Ref<T> は使えません。target field が参照先テーブルの primary key ではない場合、存在確認のために target table 側へ index が登録されます。

Actiondelete 時primary-key update 時
Restrict参照されている target の削除を拒否します。参照されている target key の移動を拒否します。
Cascadetarget を参照している source rows を削除します。source fields を新しい target key へ書き換えます。
SetNullnullable source fields を std::nullopt にします。nullable source fields を std::nullopt にします。

delete action と update action はそれぞれ 1 つだけ選べます。SetNull には std::optional<T> が必要です。

source put() 時の foreign-key validation は target の存在を確認します。non-primary target field では target-side index を使えます。

delete / update action は、参照している行を見つけるために source table を scan します。これは単純で予測しやすい挙動ですが、native indexed constraint engine の代替ではありません。

大きなテーブルで foreign-key action が hot path に入る場合は、明示的な source-side index や application-level lookup table を用意してください。

症状主な原因
target table が登録されていない参照先 entity が schema に追加されていません。
SetNull が失敗するsource field が std::optional<T> ではありません。
delete が restrict されるsource rows がまだ target を参照しています。
update が restrict されるsource rows がまだ古い target key を参照しています。
source put 時に target が見つからないsource row が存在しない target を指しています。