2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel10】`Model::withTrashed()->firstOrNew()->restore()->save()`でINSERTされない。

Posted at

どういうこと?

有効であるか論理削除されているか存在しないかいずれかわからない状態のレコードがあるけど、事前の状態に関わらず有効にして保存したい。

というわけでこんなかんじのクエリを実行したわけですよ。

だめ
class Hoge extends Model{
    use SoftDeletes;
}

$model = Hoge::withTrashed()->firstOrNew(['id'=>999]);

$model->foo = 'bar';
$model->restore();
$model->save();

これ、論理削除されたレコードがあれば論理削除が解除されてきちんと有効になりますが、存在しないレコードはINSERTされません。

なんで??????

エラーは出ないしrestore()save()もtrueを返してくるから正しく動いたと勘違いするじゃないですか。

正解はこうです。

OK
$model = Hoge::withTrashed()->firstOrNew(['id'=>999]);

$model->foo = 'bar';
$model->save();
$model->restore();

そんなんわかるか!

save()は保存時に元のデータと保存するデータで差分があるかをチェックし、差があるときだけ更新します。

restore()すると削除フラグを消してデータを保存し、その差分をリセットします。
困ったことに、まだDB上に存在しないレコードだった場合は、差分をリセットするけどデータの保存はしません。
そのせいで、save()したときに差分がないから保存しないと判断されてしまいました。

ということで試していませんが、順番を変える以外にもfirstOrNew()のかわりにfirstOrCreate()を使うと正しく動くと思います。

firstOrNew()はレコードが存在しなければ作成する、ただしDBには保存しない。
firstOrCreate()はレコードが存在しなければ作成し、DBに保存まで行う。
なので最初にfirstOrCreate()しておけば、restore()時には既にレコードが存在するから更新してくれるというわけです。

まとめ

restore()がエラーを出さないのが悪い。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?