Udemyのオススメ講座はこちら 詳細を見てみる

【Laravel】DBのデータを論理削除(Soft Delete)する方法

  • URLをコピーしました!

LaravelでDBのデータを削除する時に論理削除する方法について

  • 物理削除と論理削除の違い
  • なぜ論理削除を採用するのか

を絡めながらまとめます。

結論:論理削除のやり方はめちゃくちゃ簡単です。

目次

環境

$ composer -V
Composer version 2.0.14 2021-05-21 17:03:37

$ php artisan --version
Laravel Framework 8.53.0

Laravel6でも実装の確認済みなので、(Laravel7では未確認ですが)6系以降であればバージョンに限らず同じかと思います。

物理削除と論理削除の違い

まずは削除の中の「物理削除」「論理削除」の違いです。

物理削除論理削除
概要レコード自体を削除するテーブルに「削除扱いするか」を判定するためのカラムを設け、そのカラムの値で削除の管理・判断を行う
SQLDELETEUPDATE
メリット・DELETE文を発行するため、実装が楽
・レコードが削除される為、ストレージを圧迫しにくい
・間違えて削除されたデータの復元が簡単
・データを一時的に使用禁止とかにしやすい
デメリット・簡単にデータを復元できない
・簡単に削除したデータを参照できない
・削除してもレコードが減らないのでストレージを圧迫していく(=性能悪化に繋がる)
・SQLがUPDATEになるため直観的に理解しづらい
・検索処理時のWHERE句の条件を忘れがち
物理削除と論理削除の違い

言葉通りですが、物理的に削除する「物理削除」(そのままですみませんw)に対し、「論理削除」はデータはあるけど、システム上削除されている状態として扱う方法です。

なぜ論理削除を採用するのか

論理削除を採用するケースの多くはテーブルが以下の場合です。

  • そのテーブルで取り扱っているデータがトランザクションデータの場合(※1)
  • 削除処理するとしてもバックエンドではデータとして残しておきたいデータの場合

(※1)マスターデータの場合でも論理削除を採用する場合は多々あります。

トランザクションデータとマスターデータをそれぞれざっくりと。

データ種類概要
トランザクション
データ
蓄積されず、変更があったら値が更新されていくデータ
マスターデータ基本的に値は更新されず、蓄積されていくデータ
トランザクションデータとマスターデータについて

データ管理(復元の容易さ)や、他テーブルとのリレーション状態の保持の関係から、論理削除を採用した方が良いケースは多そうですが、それなりにデメリットもあるので根拠なしに論理削除を採用するのは良くないです。

Laravelでの論理削除の方法

前置きが長くなったのですが、Laravelでの論理削除の実装方法をご紹介します。

結論:めっちゃ簡単です。

論理削除したいテーブルにdeleted_atカラムを追加する

Laravelにデフォルトで準備してくれている仕組みとしての論理削除(ソフトデリート)ではdeleted_atカラムの値が以下のそれぞれのケースで削除されていない/削除されているを判断します。

  • NULL(デフォルト):削除されていない
  • TIMESTAMP型の値:削除されている

マイグレーションファイルにsoftDeletes()を追記することで論理削除用のdeleted_atカラムを追加することができます。

Schema::table('Users', function (Blueprint $table) {
    // 略
    $table->softDeletes();
});

softDeletes()の定義は以下のとおりです。

    /**
     * Add a "deleted at" timestamp for the table.
     *
     * @param  string  $column
     * @param  int  $precision
     * @return \Illuminate\Database\Schema\ColumnDefinition
     */
    public function softDeletes($column = 'deleted_at', $precision = 0)
    {
        return $this->timestamp($column, $precision)->nullable();
    }
  • カラム名はdeleted_at
  • データの型はTIMESTAMP
  • NULL許容

のカラムを追加しているのがわかります。

なのでそのままtimestamp()を使って定義しても問題ないです。

Schema::table('Users', function (Blueprint $table) {
    // 略
    $table->timestamp($column, $precision)->nullable();
});

ただ、softDeletes()を使った方がコード量が少ないしパッとみで論理削除することがわかる(softって書いている)のでsoftDeletes()を使う方が良いのかなと思いました。

本題とはズレますが、timestamp()の第二引数の$precisionはタイムスタンプの数字の細かさ(精度)を設定することができるようです。

論理削除したいテーブルのモデルでSoftDeletesトレイトを使う

論理削除したいテーブルに対応するモデルファイルに以下のとおりuse SoftDeletes;を追記すればOKです。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Model
{
    // 追記
    use SoftDeletes;
}

これだけです。

モデルでdeleteメソッドで削除を行う

ここまで終わったらあとはdelete()で特定のモデルインスタンスを削除すれば論理削除ができます。

かなりざっくりですが、モデルでuseしたSoftDeletesトレイトの削除時の処理を見てみます。

Model.phpdeleteメソッドでこのトレイトのperformDeleteOnModelメソッドが呼ばれる

    // 略

    public function delete()
    {
        // 略

        $this->performDeleteOnModel();

        // 略
    }

performDeleteOnModelメソッドからrunSoftDeleteが呼ばれる

    // 略

    protected function performDeleteOnModel()
    {
        // 略
        return $this->runSoftDelete();
    }

runSoftDeleteメソッドで論理削除を実行する

    // 略

    protected function runSoftDelete()
    {
        $query = $this->setKeysForSaveQuery($this->newModelQuery());

        $time = $this->freshTimestamp();

        $columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)];

        $this->{$this->getDeletedAtColumn()} = $time;

        if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
            $this->{$this->getUpdatedAtColumn()} = $time;

            $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
        }

        $query->update($columns);

        $this->syncOriginalAttributes(array_keys($columns));
    }

runSoftDeleteメソッドの処理内容はざっくりこんな感じだと思います。

  • deleted_atカラムに現在日時をセットする
  • $query->update($columns);でSQLのUPDATEを発行する

補足

Laravelで用意された論理削除機能を使うと、Eloquent(ORM)でモデルを通してDBからデータを取得する際に取得条件に削除済(deleted_atがnullではない)のモデルが含まれていても自動的に除外してくれます。

とても便利です。

公式ドキュメントにもこの記載

ソフトデリートされたモデルに対しクエリがあっても、削除済みのモデルはクエリ結果に含まれません。

最後に

この記事のまとめです。

  • なんでもかんでも論理削除にすれば良いっていうわけではない(逆も然り)
  • 論理削除を採用すべきかの感覚と経験が大事
  • フレームワークでの論理削除は簡単すぎてビビる
  • でもソースコードをちゃんと追えば処理内容は理解できる
  • データ取得時のよしなに感が最高

Laravel学習にオススメの書籍や教材はこちらにまとめています。

参考記事

Udemyのオススメ講座はこちら↓

TypeScript+Next.js+Laravelハンズオンはこちら↓

デスク周りのオススメアイテムはこちら↓

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

ブログを開設するなら「SWELL」が絶対オススメ!

この記事を書いた人

大学院(機械工学)→重工業→エンジニア→プロダクトマネージャー(PdM)兼エンジニア

神戸で「つながる勉強会」を運営↓
https://tsunagaru-kobe.connpass.com/

神戸グルメのインスタアカウントを運用しています。

目次