【Laravel官方導讀】學習Laravel Migration,看這一篇就夠了
Migration 就像是對資料庫進行的版本控制,讓你的團隊能夠輕鬆地去定義和共享應用的資料庫結構。Migration 通常配合 Laravel 的結構(Schema)生成器,可以輕鬆生成應用的資料庫結構。如果團隊中有個成員在他本地的資料庫環境中手動的添加了新欄位,那麼團們將會面對如何解決數據庫結構調整的問題
好消息是 Laravel 的 Schema facade 提供了資料庫相關的支持,可以在所有 Laravel 支持的資料庫管理系統中創建和操作表格
在這個章節我將會反覆地提到 Migration 以及 Migrate,對於新人來說不免覺得有些困惑。其實很簡單,這裡我給出說明
Migration 是名詞,代表的是準備用來變更資料庫結構的檔案,但本身無法執行。 Migrate 是動詞,它是用來執行 Migration 的內容。你搞懂了嗎?
生成 Migration 檔案
可以使用 make:migration Artisan 命令來建立 Migration 檔案。新的 Migration 文件將會放在 database/migrations 資料夾底下。 所有的 Migration 文件名稱都會包含一個時間戳記,Laravel 將據此來決定哪個 Migration 檔案要先被執行運行
php artisan make:migration create_flights_table
有意思的是, Laravel 將會使用 Migration 的檔名來猜測對應表格的名稱以及是否該 Migration 的主要目的是否為建立新表格。假如 Laravel 覺得已經能根據檔名猜出表格名稱的話,它就會為你預填好該表格的內容到 Migration 檔案內。要是檔案名稱沒有按照慣例來取的話,就需要你自己手動的填入表格名稱等結構內容
小技巧
假如你想將 Migration 檔案生成在自定義的路徑上的話,能在呼叫 make:migration 命令時使用 --path選項,該路徑須相對於專案根目錄
進階小技巧
你可以使用 stub 發布的技巧來自定義 Migration 的 stub
Migration 合併(進階技巧)
隨着時間,應用中的 Migration 會積累的越來越多。使得資料夾變得臃腫,甚至會有數百個 Migration 文件。所以如果你願意,可以將若干個 Migration 檔案,壓縮到單個 SQL 檔案中。進行這個操作,需要執行的命令是:schema:dump
完整的命令如下:
//合併但不刪除原有 Migration 文件
`php artisan schema:dump`
//合併且刪除原有 Migration 文件
php artisan schema:dump --prune
在執行以上命令後,laravel 將會把合併後的 SQL 檔案,放到專案的 database/schema 資料夾中
在進行合併操作後,當嘗試進行 migrate 操作時,在未指定 Migration 文件的預設情況下,Laravel 將會首先執行 SQL 檔案的內容。在執行 SQL 文件後,Laravel 將會繼續執行其他 Migration 檔案
Migration 的核心作用是使團隊中的其他開發人員,可以快速的創建該應用的初始資料庫結構。 所以在完成應用的資料庫架構修改後,也應該將資料庫架構文件提交至程式碼管理員、專案負責人或是 Git 版本控管平台,這能大大提高應用團隊的效率和協同能力
注意: Migration 合併功能僅適用於 MySQL,PostgreSQL 和 SQLite 資料庫,而且 SQLite還限定為非 in-memory
Migration 結構
Migration 檔案內有兩個方法: up() 和 down()。 up() 的作用是向資料庫中添加新的表格或欄位或索引,也就是這個 Migration 的主要目的。而 down() 的方法則是 up() 的反向操作,用來還原到執行 up() 之前的資料庫狀態
在這兩種方法中,你可以使用 Laravel 的 Schema 生成器很方便地去創建和修改表格。要了解 Schema 生成器上可用的所有方法,請查看相關單元
這邊來看一下,此 Migration 將創建一個 flights 表格:
//database\migrations\CreateFlightsTable.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateFlightsTable extends Migration
{
//向資料庫中添加新的 flights 表格
public function up()
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
//還原 up() 的操作,也就是刪除 flights 表格
public function down()
{
Schema::drop('flights');
}
}
設定 Migration 連線(進階技巧)
假如你的 Migration 在執行時希望不要使用預設的資料庫連線而是其他備選資料庫的話,你可以透過在 Migration 檔案內設定 $connectoin 來達到
所有的資料庫連線都被設定於 config/database.php 檔案內
//指定該 Migration 要改用名為 pgsql 的資料庫連線
//database\migrations\CreateFlightsTable.php
protected $connection = 'pgsql';
執行 Migrate
要執行所有還未執行的 Migration ,只需執行以下的 Artisan 命令
php artisan migrate
假如你想知道到目前有哪些 Migration 已經執行完畢,你可以使用 migrate:status 指令又或者去看 migrations 表格都是一樣的
php artisan migrate:status
在正式環境中強制執行 Migrate
有些 Migrate 操作是有破壞性的,這意味着它們可能會導致資料消失。為了防止你不小心對生式資料庫運行這些命令,在執行這些命令之前,系統將提示你進行最後確認。如果要在運行強制命令的時候去掉提示,請使用 -force 選項:
php artisan migrate --force
還原 Migration
要返回到最後一次操作,你可以使用 rollback 命令。此命令會返回到最後 「一批」 的 Migration 狀態,這操作可能會包含多個位於同一批的 Migration 文件:
它實作還原的作法是甚麼? 就是呼叫你所實作的 down(),搞明白了嗎?
php artisan migrate:rollback
如果在 rollback 命令的後面加上 step 選項,可以指定要還原的 Migration 數量。例如,以下命令將還原最後 5 個 Migration:
php artisan migrate:rollback --step=5
migrate:reset 是最具破壞力的一種操作,它將會還原應用中所有的 Migration
一鍵同時進行還原與 Migrate
使用 migrate:refresh 命令將會還原所有 Migration 操作,然後 Laravel 將繼續執行 migrate 命令以進行重新 Migrate。同時可在該命令後加上 --seed, 這個選項的作用是在 「刷新」 完成數據庫之後,順便執行 Seed 以生成資料
如需使用 Seed 功能,你還必須自己實作各表格的 Seeder 類別
範例:
//重置所有 Migration
php artisan migrate:refresh
//重置所有 Migration 並同時建立資料
php artisan migrate:refresh --seed
之前所介紹過的 --step 選項,在這裡同樣適用,請參考這個例子
//重置 5 個 Migration 檔案
php artisan migrate:refresh --step=5
資料表
建立資料表
我們將示範用 Schema 生成器的 create() 來創建一個新的資料表。 create() 中可以接受兩個參數,一個是表格的名稱,第二個是 Closure,作用是可以在定義新資料表的時候得到 Blueprint 物件,看例子比較好理解:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->timestamps();
});
有了 Blueprint 物件,你就能用它的各種欄位方法來定義表格裡的欄位
確認表格 & 欄位是否存在
你能使用 hasTable 以及 hasColumn 方法來確認表格或欄位是否存在
if (Schema::hasTable('users')) {
// "users" 表格存在...
}
if (Schema::hasColumn('users', 'email')) {
// "users" 表格存在並包含 "email" 欄位...
}
資料庫連接 & 表格選項
如果要對非預設連接的資料庫連接執行結構操作,可以使用 connection():
Schema::connection('sqlite')->create('users', function (Blueprint $table) {
$table->id();
});
你也可以在 Schema 生成器上使用以下作法來定義表格的選項,比如當使用 MySQL 時的 storage engine:
Schema::create('users', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
// ...
});
| 屬性操作 | 說明 |
|---|---|
| $table->engine = 'InnoDB'; | 指定表格儲存引擎 (MySQL) |
| $table->charset = 'utf8mb4'; | 指定資料表的預設字符集 (MySQL) |
| $table->collation = 'utf8mb4_unicode_ci'; | 指定資料表預設的排序規則 (MySQL) |
| $table->temporary(); | 創建臨時表格 (不支持 SQL Server) |
更新表格
Schema facade 的 table() 用於更新已有的表格。就像 create() ,它接受兩個參數: 表格名稱以及 Closure。而 Closure 同樣會得到 Blueprint 實例用來新增或索引表格:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});
表格更名 & 刪除
如果要更名一個已存在的資料庫表格,使用 rename():
use Illuminate\Support\Facades\Schema;
Schema::rename($from, $to);
如果要刪除一個已存在的資料庫表格,使用 drop() 或 dropIfExists()
//一定要刪到 users 表格
Schema::drop('users');
//如果 users 表格存在才刪除
Schema::dropIfExists('users');
重命名帶外鍵關係的資料表(進階知識)
在重命名表格之前,你應該確認表格上的任何外鍵關係在 Migration 文件中都有明確的名稱,而不是讓 Laravel 按照預設來設置一個名稱。否則外鍵的關係名稱將引用舊表格名
欄位
建立欄位
之前有說過,你能夠利用 Closure 所得到的 Illuminate\Database\Schema\Blueprint 實例來建立表格欄位:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});
可使用的欄位類型
資料庫 Schema 生成器包含表格常用的各種欄位類型,如下所列:
| 程式碼 | 說明 |
|---|---|
| $table->id(); | $table->bigIncrements('id') 的別名 |
| $table->foreignId('user_id'); | $table->unsignedBigInteger('user_id') 的別名 |
| $table->bigIncrements('id'); | 遞增 ID(主鍵),相當於「UNSIGNED BIG INTEGER」 |
| $table->bigInteger('votes'); | 相當於 BIGINT |
| $table->binary('data'); | 相當於 BLOB |
| $table->boolean('confirmed'); | 相當於 BOOLEAN |
| $table->char('name', 100); | 相當於帶有長度的 CHAR |
| $table->date('created_at'); | 相當於 DATE |
| $table->dateTime('created_at', 0); | 相當於 DATETIME ,可以指定位數 |
| $table->dateTimeTz('created_at', 0); | 相當於 DATETIME (帶時區) ,可以指定位數 |
| $table->decimal('amount', 8, 2); | 相當於 DECIMAL,可以指定總位數和小數位數 |
| $table->double('amount', 8, 2); | 相當於 DOUBLE,可以指定總位數和小數位數 |
| $table->enum('level', ['easy', 'hard']); | 相當於 ENUM |
| $table->float('amount', 8, 2); | 相當於 FLOAT,可以指定總位數和小數位數 |
| $table->geometry('positions'); | 相當於 GEOMETRY |
| $table->geometryCollection('positions'); | 相當於 GEOMETRYCOLLECTION |
| $table->increments('id'); | 遞增 ID(主鍵),相當於 UNSIGNED INTEGER |
| $table->integer('votes'); | 相當於 INTEGER |
| $table->ipAddress('visitor'); | 相當於 IP 地址 |
| $table->json('options'); | 相當於 JSON |
| $table->jsonb('options'); | 相當於 JSONB |
| $table->lineString('positions'); | 相當於 LINESTRING |
| $table->longText('description'); | 相當於 LONGTEXT |
| $table->macAddress('device'); | 相當於 MAC 地址 |
| $table->mediumIncrements('id'); | 遞增 ID(主鍵),相當於 UNSIGNED MEDIUMINT |
| $table->mediumInteger('votes'); | 相當於 MEDIUMINT |
| $table->mediumText('description'); | 相當於 MEDIUMTEXT |
| $table->morphs('taggable'); | 相當於加入遞增 UNSIGNED BIGINT 類型的 taggable_id 與字串類型的 taggable_type |
| $table->uuidMorphs('taggable'); | 相當於添加一個 CHAR (36) 類型的 taggable_id 欄位和 VARCHAR (255) UUID 類型的 taggable_type |
| $table->multiLineString('positions'); | 相當於 MULTILINESTRING |
| $table->multiPoint('positions'); | 相當於 MULTIPOINT |
| $table->multiPolygon('positions'); | 相當於 MULTIPOLYGON |
| $table->nullableMorphs('taggable'); | 添加一個可以為空版本的 morphs() 欄位 |
| $table->nullableUuidMorphs('taggable'); | 添加一個可以為空版本的 uuidMorphs() 欄位 |
| $table->nullableTimestamps(0); | timestamps() 方法的別名 |
| $table->point('position'); | 相當於 POINT |
| $table->polygon('positions'); | 相當於 POLYGON |
| $table->rememberToken(); | 添加一個允許空值的 VARCHAR (100) 類型的 remember_token 欄位 |
| $table->set('flavors', ['strawberry', 'vanilla']); | 相當於 SET |
| $table->smallIncrements('id'); | 遞增 ID(主鍵),相當於 UNSIGNED SMALLINT |
| $table->smallInteger('votes'); | 相當於 SMALLINT |
| $table->softDeletes('deleted_at', 0); | 相當於為軟刪除添加一個可為空值的 deleted_at 欄位 |
| $table->softDeletesTz('deleted_at', 0); | 相當於為軟刪除添加一個可為空值的帶時區的 deleted_at 欄位 |
| $table->string('name', 100); | 相當於指定長度的 VARCHAR |
| $table->text('description'); | 相當於 TEXT |
| $table->time('sunrise', 0); | 相當於指定位數的 TIME |
| $table->timeTz('sunrise', 0); | 相當於指定位數帶時區的 TIME |
| $table->timestamp('added_on', 0); | 相當於指定位數的時間戳記 |
| $table->timestampTz('added_on', 0); | 相當於指定位數帶時區的時間戳記 |
| $table->timestamps(0); | 相當於添加可為空值的時間戳記類型的 created_at 和 updated_at |
| $table->timestampsTz(0); | 相當於添加指定時區的可為空值的時間戳記類型的 created_at 和 updated_at |
| $table->tinyIncrements('id'); | 相當於自動遞增 UNSIGNED TINYINT |
| $table->tinyInteger('votes'); | 相當於 TINYINT |
| $table->unsignedBigInteger('votes'); | 相當於 UNSIGNED BIGINT |
| $table->unsignedDecimal('amount', 8, 2); | 相當於 UNSIGNED DECIMAL ,可以指定總位數和小數位數 |
| $table->unsignedInteger('votes'); | 相當於 UNSIGNED INTEGER |
| $table->unsignedMediumInteger('votes'); | 相當於 UNSIGNED MEDIUMINT |
| $table->unsignedSmallInteger('votes'); | 相當於 UNSIGNED SMALLINT |
| $table->unsignedTinyInteger('votes'); | 相當於 UNSIGNED TINYINT |
| $table->uuid('id'); | 相當於 UUID |
| $table->year('birth_year'); | 相當於 YEAR |
欄位修飾子
你還可以在剛列出的欄位定義方法後面搭配欄位修飾子。例如,如果要把欄位設置為「可為空值」,就可以使用 nullable():
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});
以下是所有可用的欄位修飾子的列表,不包括索引修飾子:
| 修飾子 | 說明 |
|---|---|
| ->after('column') | 將此欄位放置在其它欄位 「之後」 (MySQL) |
| ->autoIncrement() | 將 INTEGER 類型的欄位設置為自動遞增的主鍵 |
| ->charset('utf8mb4') | 指定一個字符集 (MySQL) |
| ->collation('utf8mb4_unicode_ci') | 指定排序規則 (MySQL/PostgreSQL/SQL Server) |
| ->comment('my comment') | 為欄位增加注釋 (MySQL/PostgreSQL) |
| ->default($value) | 為欄位指定 「預設」 值 |
| ->first() | 將此欄位放置在數據表的 「首位」 (MySQL) |
| ->from($integer) | 給自增欄位設置一個起始值 (MySQL / PostgreSQL) |
| ->nullable($value = true) | 此欄位允許寫入 NULL 值(預設情況下) |
| ->storedAs($expression) | 創建一個存儲生成的欄位 (MySQL) |
| ->unsigned() | 設置 INTEGER 類型的欄位為 UNSIGNED (MySQL) |
| ->useCurrent() | 將 TIMESTAMP 類型的欄位設置為使用 CURRENT_TIMESTAMP 作為預設值 |
| ->virtualAs($expression) | 創建一個虛擬生成的欄位 (MySQL) |
| ->generatedAs($expression) | 使用指定的序列生成標識列(PostgreSQL) |
| ->always() | 定義序列值優先於標識列的輸入 (PostgreSQL) |
default 修飾子接收一個變數或者一個 \Illuminate\Database\Query\Expression 實例。使用 Expression 實例可以避免使用包含在引號中的值,並且允許你使用特定資料庫函數。這在當你需要給 JSON 欄位指定預設值的時候特別有用:
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Migrations\Migration;
class CreateFlightsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('flights', function (Blueprint $table) {
$table->id();
$table->json('movies')->default(new Expression('(JSON_ARRAY())'));
$table->timestamps();
});
}
}
注意:
支持哪些預設值的 Expression 表示方式取決於你的資料庫驅動、版本、還有欄位類型,使用前請先詳閱資料庫公開說明書
欄位順序(進階技巧)
如果你使用的是 MySQL 資料庫,after() 用來讓你將新定義的欄位擺在已存在的表格欄位之後:
$table->after('password', function ($table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});
修改欄位
前置準備
如需修改欄位,請確保將 doctrine/dbal 套件安裝到專案內。Doctrine DBAL 套件用於確定欄位的當前狀態, 並創建對該欄位進行指定調整所需的 SQL 查詢,以下是安裝套件的指令:
composer require doctrine/dbal
假如你準備修改原本是用 timestamp() 所生成的欄位,你需要加入以下的設定到應用的資料庫設定檔 config/database.php
//config\database.php
use Illuminate\Database\DBAL\TimestampType;
'dbal' => [
'types' => [
'timestamp' => TimestampType::class,
],
],
假如你的應用使用的是 Microsoft SQL Server,請確保有安裝 doctrine/dbal:^3.0 版本
更新欄位屬性
change() 方法可以將現有的欄位類型修改為新的類型或修改它的屬性。比如,你可能想增加字串欄位的長度,可以使用 change() 把 name 欄位的長度從 25 增加到 50:
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->change(); //把欄位長度改為50
});
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->nullable()->change(); //把欄位改為可為空值
});
注意:
只有以下欄位類型能被修改:bigInteger、binary、boolean、date、dateTime、dateTimeTz、decimal、integer、json、 longText、mediumText、smallInteger、string、text、time、unsignedBigInteger、unsignedInteger 和 unsignedSmallInteger 以及 uuid。如果要修改 timestamp 欄位需要先註冊 Doctrine 類型
欄位更名
可以使用 Schema 生成器上的 renameColumn() 來重命名欄位。在重命名欄位前,請確保你的應用已經下載過 doctrine/dbal 套件,可透過檢查 composer.json 文件來確認:
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});
注意:
目前版本不支持 enum 類型的欄位重命名
欄位刪除
可以使用 Schema 生成器上的 dropColumn() 方法來刪除欄位,同樣需要 doctrine/dbal 套件:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});
你可以傳遞一個字串陣列給 dropColumn() 來一次刪除多個欄位:
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
注意:
使用 SQLite 資料庫時不支持在單個 Migration 中刪除或修改多個欄位
可用的命令別名
Laravel 提供了幾個方便的方法來刪除內建的欄位,列表於下:
| 命令 | 說明 |
|---|---|
| $table->dropMorphs('morphable'); | 刪除 morphable_id 和 morphable_type 字段 |
| $table->dropRememberToken(); | 刪除 remember_token 字段 |
| $table->dropSoftDeletes(); | 刪除 deleted_at 字段 |
| $table->dropSoftDeletesTz(); | dropSoftDeletes() 方法的別名 |
| $table->dropTimestamps(); | 刪除 created_at 和 updated_at 字段 |
| $table->dropTimestampsTz(); | dropTimestamps() 方法別名 |
索引
建立索引
Schema 生成器支持多種類型的索引。下面的例子中新建了一個值唯一的 email 欄位。我們可以將 unique() 串到欄位定義後面來創建索引:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});
或者,你也可以在定義完欄位之後創建索引。例如:
$table->unique('email');
你甚至可以將陣列傳遞給索引方法來創建一個複合索引:
$table->index(['account_id', 'created_at']);
Laravel 會自動生成一個合理的索引名稱,但你也可以傳遞第二個參數來自定義索引名稱:
$table->unique('email', 'unique_email');
可用的索引類型
每個索引方法都接受一個可選的第二個參數來指定索引的名稱。如果省略的話,名稱將根據表格和欄位的名稱來生成
| 命令 | 說明 |
|---|---|
| $table->primary('id'); | 添加主鍵 |
| $table->primary(['id', 'parent_id']); | 添加複合鍵 |
| $table->unique('email'); | 添加唯一索引 |
| $table->index('state'); | 添加普通索引 |
| $table->spatialIndex('location'); | 添加空間索引(不支持 SQLite) |
MySQL 和 MariaDB 的索引長度
Laravel 預設使用 utf8mb4 編碼,它支持在資料庫中儲存表情符號(emojis)。如果你是在版本低於 5.7.7 的 MySQL 或者版本低於 10.2.2 的 MariaDB 上創建索引,那你就需要手動配置 Migration 的預設字串長度。
作法就是在 AppServiceProvider 中調用 Schema::defaultStringLength() 來配置它:
//app\Providers\AppServiceProvider.php
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
重命名索引
若要重命名索引,你需要呼叫 Schema 生成器的 blueprint 物件所提供的 renameIndex()。此方法接受當前索引名稱作為其第一個參數,並將所需名稱作為其第二個參數:
$table->renameIndex('from', 'to')
刪除索引
若要刪除索引,則必須指定索引的名稱。Laravel 預設會自動將資料表名稱、索引的欄位名及索引類型簡單地連接在一起作為名稱。舉例如下:
| 命令 | 說明 |
|---|---|
| $table->dropPrimary('users_id_primary'); | 從 「users」 表中刪除主鍵 |
| $table->dropUnique('users_email_unique'); | 從 「users」 表中刪除 unique 索引 |
| $table->dropIndex('geo_state_index'); | 從 「geo」 表中刪除基本索引 |
| $table->dropSpatialIndex('geo_location_spatialindex'); | 從 「geo」 表中刪除空間索引(不支持 SQLite) |
如果將字串陣列傳給 dropIndex() ,會刪除根據表格名稱、欄位和索引類型生成的索引名稱
Schema::table('geo', function (Blueprint $table) {
$table->dropIndex(['state']); // Drops index 'geo_state_index'
});
外鍵約束
Laravel 還支持創建用於在資料庫層中的強制引用完整性的外鍵約束。例如,讓我們在 posts 表格上定義一個參考到 users 表格的 id 欄位的 user_id 欄位:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});
由於這種外鍵約束的定義方式過於繁複,Laravel 額外提供了更簡潔的方法來提供更好的開發人員體驗,因此上面的範例還可以這麼寫:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
});
foreignId() 是 unsignedBigInteger 的別名,而 constrained() 將使用命名慣例來確定所參考的表格名和欄位名。如果表格名與命名慣例不匹配,可以通過將表格名作為參數傳遞給 constrained() 來指定表格名:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained('users');
});
你也可以為外鍵約束的「on delete」和「on update」屬性指定所需的操作:
$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');
如果有需要使用其他的欄位修飾子時,務必在呼叫 constrained() 之前先呼叫:
$table->foreignId('user_id')
->nullable()
->constrained();
刪除外鍵
要刪除一個外鍵,你需要使用 dropForeign() ,將要刪除的外鍵約束作為參數傳遞。外鍵約束採用的命名方式與索引相同。即將資料表名稱和約束的欄位連接起來,再加上 "_foreign" 後綴:
$table->dropForeign('posts_user_id_foreign');
或者,可以給 dropForeign() 傳遞一個陣列,該陣列包含要刪除的外鍵的欄位名。陣列將根據 Laravel 的 Schema 生成器使用的約束名稱約定自動轉換:
$table->dropForeign(['user_id']);
你可以在 Migration 中使用以下方法來開啟或關閉外鍵約束:
Schema::enableForeignKeyConstraints();
Schema::disableForeignKeyConstraints();
注意:
SQLite 預設禁用外鍵約束。使用 SQLite 時,請確保在資料庫配置中啟用"啟用外鍵支持",然後再嘗試在 Migration 中創建它們。另外,SQLite 只在創建表格時支持外鍵,並且在修改表格時就不會了



