Oren Eini氏(Ayende Rahienと名乗っている)が、読み手に物理削除の代替案だと思われるような論理削除はやめたほうがいい とblogにかいたところ、Udi Dahan氏は削除自体をやめるべきだと強く主張している。
論理削除は実現するには、IsDeleted列をテーブルに加えてデータをそのまま残しておくようにする。その行が削除されたことになるのは、IsDeleted列のフラグが立ったときだ。 Ayende氏は、この方法は単純で、理解しやすく、実装も説明を素早くできるが、間違いが起きやすいと考えている。問題は、
行やエンティティの削除は単純な処理ではありません。モデルの中のデータだけでなく、モデルの輪郭にまで影響を与えます。だから外部キーを設定し、例えば、注文詳細エンティティに親である注文エンティティがないという状態になってしまわないようにします。しかし、これは最も単純な問題にすぎません。…
論理削除をするときは、あらゆる点から考えても、データが汚れてしまっているという状況になってしまいがちです。例えば、顧客エンティティがが最新の注文エンティティ(これはとても単純化したモデルにすぎませんが)を保持している場合、論理削除された最後の注文エンティティを保持してしまうことがあるからです。
データベースからデータを削除しなければならなくて、論理削除が推奨されないのなら物理削除しかない。データの完全性を保持するため、関連するデータも一緒にカスケード削除する。しかし、Udi Dahan氏が指摘するのは、現実の世界ではカスケード削除は行われないということだ。
例えば、マーケティング部門がカタログからある商品を削除するとします。ではこのとき、この商品への以前の注文も一緒に消えてなくなるのでしょうか。さらにカスケードして、請求書も削除されるのでしょうか。さらに、会社の利益や損益ももとに戻るのでしょうか。
そんなことはありえません。
どうやら問題は“delete”を対する解釈にあるようだ。Dahan氏は次のような例えを挙げている。
例えば‘delete’という言葉で私が言いたいのは、次のようなことだとします。つまり、その商品が中止になり、これ以上その製品を売りたくない。在庫はすべて処理したいが、サプライヤからは注文を受けない。顧客が商品を検索したり目録を調べたりするときに、その商品が現われないようにしたい。でも倉庫で働く人は、しばらくの間その商品を管理できる。けれどもこれらのことは‘delete’の一言で表しきれません。
氏は続けてユーザの意図の正確な解釈について考えている。
注文は削除されません。– キャンセルされるのです。キャンセルが遅かったら、料金が発生するでしょう。
従業員は削除されません。– 解雇されるのです(あるいは退職かもしれません)。 給与体系は頻繁に手を入れなければなりません 。
仕事も削除されません。– 完了されるのです(または、取り消されるかもしれません)。
どんな場合でも、着目すべきはユーザが行いたい作業であり、エンティティその他に対する技術的な処理ではありません。ユーザの作業に着目すれば、ほとんどすべての場合、1つ以上のエンティティを考慮しなければならないはずです。
IsDeletedフラグを使う代わりに、Dahan氏はデータの状態を表すフィールドを保持することを提案している。例えば、有効、中止、キャンセル、廃止予定のような状態だ。このような状態フィールドがあれば、ユーザは過去にさかのぼって古いデータを追跡し、意思決定に役立てることもできる。
データの削除はデータの完全性に悪影響を及ぼす可能性がある。Dahan氏が奨めるのはすべてのデータをデータベースに残すことだ。 “削除するな、絶対に”