コトの発端
Laravel Eloquentのリレーション機能いいよね。
親モデルのHasManyで取得したオブジェクトから子レコードを追加したいと思った。
$dat = $this->hasMany(Support_detail::class,'support_id');
$dat->create(['detail_note' => 'memo'.date("Ymd")]);
しかし、上記のコードを実行してみたところ、親テーブルの主キーは親のレコードから勝手に持ってきてくれていたが、子テーブルのキーは設定されなかった。
SQLSTATE[HY000]: General error: 1364 Field 'detail_no' doesn't have a default value
子テーブルの主キーは、support_id, detail_noとしているが、support_idしか入っていない。AUTO_INCREMENTを設定していないからそれはそう。この複合主キーで、そのうちのsupport_idにAUTO_INCREMENTが設定されていれば解決できそう。
まずは結論
前置きが長くなったので結論から。
マイグレーション全文
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if(!Schema::hasTable('support_details')){
Schema::create('support_details', function (Blueprint $table) {
$table->foreignId('support_id')->nullable(false);
$table->id('detail_no')->unique();
$table->text('detail_note')->default(NULL);
$table->softDeletesDatetime();
$table->timestamps();
$table->comment('サポート詳細');
});
Schema::table('support_details', function (Blueprint $table) {
$table->dropPrimary();
$table->primary(['support_id','detail_no',]);
});
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('support_details');
}
};
ポイント
- $table->id('detail_no')->unique(); AUTO_INCREMENTにしたいカラムにunique()をつける。
- create後にdropPrimary()で主キーを外し、primary(['support_id','detail_no',])で複合主キーを作成。
解説のようなもの
Laravelのマイグレーションの仕様上、AUTO_INCREMENTを設定しようとすると強制的に主キーになり、それ以外のカラムを$table->primary()などで主キーに追加しようとすると、1068 Multiple primary key definedのエラーが発生する。
これは、2カ所以上でプライマリキーを設定しようとしているというエラーであるため、create後に勝手に追加されたid列の主キーを外そうとするも、AUTO_INCREMENTを設定するカラムはプライマリキーかユニークキーが設定されている必要があり、それを満たせなくなるためエラーとなる。
そのためidカラムにuniqueを設定する。
実行すると複合主キーとオートインクリメントが設定されたテーブルが生成される。
当初やりたかった、hasManyで取得したオブジェクトに対してcreateするということもできた。
データ挿入するときに親子両方のキーを指定しなくてもいいのはらくらくで良き。めでたしめでたし。
おまけ
idカラムにunique()をつけてマイグレーションしただけのテーブルをMariaDBで確認したところ、そのidカラムはユニークキーではなくプライマリキーに設定されていた。不思議。
uniqueをcreate時につけていると、dropPrimaryをしたときにuniqueに置き換わるのかな?(未検証)
ここから続けて下記が実行されると、なぜか
いつもの
記事の内容は無保証です。