PHP データベース プログラミング 技術解説

Laravel10 複合主キーかつAUTO_INCREMENTを持つテーブルを作成するマイグレーションファイルの書き方

コトの発端

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に置き換わるのかな?(未検証)

ここから続けて下記が実行されると、なぜか

いつもの

記事の内容は無保証です。

  • この記事を書いた人
あっきー

あっきー

とある企業の研究者。研究分野以外に手を出しすぎて毎日が慌ただしい。 研究者の肩書きが正しいかどうかは万年の謎。 得意ジャンルはデータベースとセキュリティーですが、AIやIoT、アプリ開発など、手広く活動しています。

-PHP, データベース, プログラミング, 技術解説
-, ,

Translate »