論理削除の概念
論理削除は、データベースのレコードを物理的に削除する代わりに、削除されたことを示すフラグ(通常はdeleted_at
カラム)を設定する方法です
コレにより、データは実際にはデータベースに残り続けますが、アプリケーション上では削除されたものとして扱われます
メリット
- データの復元が容易
- 誤って削除したデータを復元するのが簡単です
- 履歴管理
- 削除の履歴を追跡でき、監査やログ管理が容易になります
- 参照整合性の維持
- 削除されたレコードを参照しようとしても有効なデータとして参照できる
- データを完全に削除(物理削除)した場合は参照できなくなってしまいます
デメリット
- ストレージ増加
- 完全にデータを削除しないため、ストレージが増加します
- クエリの複雑化
- 削除されたレコードを無視するための条件を追加する必要があります
- パフォーマンスの低下
- 大量の論理削除データがあると、パフォーマンスが低下する可能性があります
論理削除を使う場面
- データの復元が必要な場合
- 監査や履歴管理が必要な場合
- 参照整合性を維持する必要がある場合(論理削除済みデータも取得したい場合)
論理削除を使う場面において実際に使う場合と使わない場合の違い
論理削除を使う場合
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
}
// データの削除
$post->delete();
// 削除されたデータの取得
$deletedPosts = Post::onlyTrashed()->get();
// データの復元
$post->restore();
論理削除を使わない場合
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
// ソフトデリートなし
}
// データの削除
$post->delete();
// 削除されたデータは取得できない
$deletedPosts = Post::whereNotNull('deleted_at')->get(); // 手動で管理する必要がある
テーブルに論理削除を定義し、Laravelで設定する方法
(前項と一部重複する部分があります)
まず、テーブルにdeleted_at
カラムを追加する必要があります
マイグレーションファイルの作成
Schema::table('posts', function (Blueprint $table) {
$table->softDeletes();
});
モデルでの設定
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use SoftDeletes;
protected $dates = ['deleted_at'];
}
カスタムカラムを使った論理削除
deleted_at
以外のカラムを使って論理削除を実装することもできます
例えば、deleted
と言うカラム使用します
マイグレーションファイルでのテーブル定義
Schema::table('posts', function (Blueprint $table) {
$table->timestamp('deleted')->nullable();
});
モデルでの設定
カスタムカラムを使用するためには、SoftDeletes
トレイトをカスタマイズします
<?php
namespace App;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
// 論理削除をON.
use SoftDeletes;
// 論理削除に使うカラム名を指定(ここでは「deleted」)
const DELETED_AT = 'deleted';
// 日付として扱うカラムを定義(ここに論理削除に使うカラムも指定する)
protected $dates = ['deleted'];
}
GoodパターンとNGパターン
Goodパターン
LarravelのEloquentソフトデリート機能を利用する
$post->delete();
NGパターン
生SQLで論理削除を行う
生SQLクエリを直接使用して論理削除を実行することは避けるべきです。これにより、Eloquentの便利な機能(スコープ、リレーション管理、イベント)が使えなくなり、メンテナンス性が低下します
DB::statement("UPDATE posts SET is_deleted = 1 WHERE id = ?", [$postId]);
理由:
- Eloquentのソフトデリート機能を無視している
- クエリ実行が直接的で、コードの可読性が低い
- Eloquentイベント(例えば、削除時イベント)がトリガーされない
実際の現場ではどのような場面で使っているのか
- ユーザーデータの削除
- ユーザーがアカウントを削除した場合でも、後で復元できるように論理削除を使用します
- 製品データの管理
- 製品が廃止された場合でも、過去のデータを保持しておくために論理削除を使用します
まとめ
論理削除を使うことで、削除されたレコードを他のレコードが参照している場合でも、
そのレコードの情報を保持し続けることができます
実はこのケースは前述が代表例であって結構あるんですよね
論理削除を使うことで、データベース内の参照整合性を維持し、削除されたデータの復元や履歴の追跡が容易になります
テーブル設計に合わせて設定していきましょう!