Laravelでプライマリキーを使った1:1関連のテーブル分割で自動採番をしないようにする
- プライマリキーを使った1:1関連でカラム数の多いテーブルを分割する - Hidden in Plain Sight
- プライマリキーを使った1:1関連のテーブル分割で自動採番をしないようにする - かみぽわーる
を Laravel でも同じようにできるよな。と思って書いてみたらちょっとハマったので Laravel 使っている人は気をつけましょうという話。
問題はカラム毎に charset の指定ができないので、カラム長を 255 にして utf8mb4 を default charset にするといわゆる 767bytes 問題が発生する。
解決方法としては
DB::statement
を使用してALTER TABLE
してカラムの charset を指定する。- カラム長を短くする。
- utf8mb4 をやめる。
2 と 3 は 根本的な解決にはなりませんよね?*1 というわけで 1 の方法で解決をはかりましょう。
マイグレートファイル
users
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function(Blueprint $table) { $table->increments('id'); $table->string('email')->unique(); $table->string('password'); $table->timestamps(); $table->index('email'); }); DB::statement('ALTER TABLE users MODIFY email varchar(255) CHARACTER SET ascii COLLATE ascii_bin'); DB::statement('ALTER TABLE users MODIFY password varchar(255) CHARACTER SET ascii COLLATE ascii_bin'); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('users'); } }
profiles
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; class CreateProfilesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('profiles', function(Blueprint $table) { $table->integer('id')->unsigned(); $table->string('name')->nullable(); $table->tinyInteger('gender')->nullable(); $table->dateTime('birthday')->nullable(); $table->timestamps(); $table->primary('id'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('profiles'); } }
で OK です。
最後に
migrate の SQL を確認したいときは pretend
オプションをつけると確認できます。
上記 2 テーブルのマイグレート SQL はこんな感じです。
$php artisan migrate --pretend CreateUsersTable: create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null, `password` varchar(255) not null, `created_at` timestamp default 0 not null, `updated_at` timestamp default 0 not null) default character set utf8 collate utf8mb4 CreateUsersTable: alter table `users` add index users_email_index(`email`) CreateUsersTable: alter table `users` add unique users_email_unique(`email`) CreateUsersTable: ALTER TABLE users MODIFY email varchar(255) CHARACTER SET ascii COLLATE ascii_bin CreateUsersTable: ALTER TABLE users MODIFY password varchar(255) CHARACTER SET ascii COLLATE ascii_bin CreateProfilesTable: create table `profiles` (`id` int unsigned not null, `name` varchar(255) null, `gender` tinyint null, `birthday` datetime null, `created_at` timestamp default 0 not null, `updated_at` timestamp default 0 not null) default character set utf8 collate utf8mb4 CreateProfilesTable: alter table `profiles` add primary key profiles_id_primary(`id`)
(追記)モデルの実装
モデルではこんな感じ。hasOne
及び belongsTo
の第2引数がポイントです。
<?php class User extends Eloquent { public function profile() { return $this->hasOne('Profile', 'id'); } } class Profile extends Eloquent { public function user() { return $this->belongsTo('User', 'id'); } } $profile = User::find(1)->profile;
*1:ぜひ、リンクを踏んでイラッとしていただきたい