Posted at

Laravelのseederを冪等にする

seederを冪等に作成しておかないと、重複してはいけないデータが存在した場合に、2度目の実行時にエラーが発生してしまいます。

そのため、データがなければ作成してすでに存在していれば作成をしないようにするような書き方について調べました。


そもそも冪等とは

wikipediaによると


ある操作を1度行っても複数回行っても同じ効果となることを言う。特に、何回行ってもエラーや不整合の状態が変わらない操作を指す。



firstOrCreateを使う

firstOrCreateを使用することで、データが存在すればそれを取得するし、なければ新しく作成してくれます。


firstOrCreateメソッドは指定されたカラム/値ペアでデータベースレコードを見つけようします。モデルがデータベースで見つからない場合は、最初の引数が表す属性、任意の第2引数があればそれが表す属性も同時に含む、レコードが挿入されます。



firstOrCreateで作成されたのかどうかはwasRecentlyCreatedで判定をする

モデルのインスタンスのwasRecentlyCreated で判定ができます。

// 初回の実行

>>> $user = App\User::firstOrCreate(['name' => 'hoge', 'email' => 'hoge2@hoge.com', 'password' => 'hoge2']);
=> App\User {#2901
name: "hoge",
email: "hoge2@hoge.com",
updated_at: "2019-07-15 23:11:35",
created_at: "2019-07-15 23:11:35",
id: 53,
}
// 作成されたのでtrueになる
>>> $user->wasRecentlyCreated;
=> true
// 再度実行して取得する
>>> $user = App\User::firstOrCreate(['name' => 'hoge', 'email' => 'hoge2@hoge.com', 'password' => 'hoge2']);
=> App\User {#2900
id: 53,
name: "hoge",
email: "hoge2@hoge.com",
created_at: "2019-07-15 23:11:35",
updated_at: "2019-07-15 23:11:35",
stripe_id: null,
card_brand: null,
card_last_four: null,
trial_ends_at: null,
}
// 作成されていないのでfalseになる
>>> $user->wasRecentlyCreated;
=> false


これらを組み合わせてseederを作成する

一部分ですが、複数回実行するとデータが重複してエラーになる箇所は、firstOrCreate で作成をして、wasRecentlyCreated がtrueの場合のみそれにひもづくデータを作成するようにすれば、何度実行しても同じ結果となります。

$user = User::firstOrCreate(['name' => 'hoge']);

// 今回作成された場合にはtrueになる
if ($user->wasRecentlyCreated) {
// userにひもづくデータをここで作成する
}