資料庫:Seeding
簡介
在 Laravel 中,我們可以使用 Seed 類別來為資料庫提供初始資料。Seed 類別存放在 database/seeders
目錄中。預設情況下,Laravel 中已定義了一個 DatabaseSeeder
類別。在這個類別中,我們可以呼叫 call
方法來執行其他 Seed 類別,好讓我們能控制資料填充的順序。
在進行 Seeder 時,會自動禁用大量賦值保護。
撰寫 Seeder
若要產生 Seeder,請執行 make:seeder
Artisan 指令。Laravel 所產生的所有 Seeder 都會放在 database/seeders
目錄下:
1php artisan make:seeder UserSeeder
1php artisan make:seeder UserSeeder
Seeder 類別中預設只包含了一個方法:run
。執行 db:seed
Artisan 指令 時,會呼叫該方法。在 run
方法中,我們可以任意將資料寫入資料庫內。我們可以使用 Query Builder 來手動寫入資料,或是使用 Eloquent Model Factory 來寫入資料。
來看看一個範例,讓我們來修改預設的 DatabaseSeeder
類別,並在 run
方法內新增一個資料庫 Insert 陳述式:
1<?php23namespace Database\Seeders;45use Illuminate\Database\Seeder;6use Illuminate\Support\Facades\DB;7use Illuminate\Support\Facades\Hash;8use Illuminate\Support\Str;910class DatabaseSeeder extends Seeder11{12 /**13 * Run the database seeders.14 */15 public function run(): void16 {17 DB::table('users')->insert([18 'name' => Str::random(10),19 'email' => Str::random(10).'@gmail.com',20 'password' => Hash::make('password'),21 ]);22 }23}
1<?php23namespace Database\Seeders;45use Illuminate\Database\Seeder;6use Illuminate\Support\Facades\DB;7use Illuminate\Support\Facades\Hash;8use Illuminate\Support\Str;910class DatabaseSeeder extends Seeder11{12 /**13 * Run the database seeders.14 */15 public function run(): void16 {17 DB::table('users')->insert([18 'name' => Str::random(10),19 'email' => Str::random(10).'@gmail.com',20 'password' => Hash::make('password'),21 ]);22 }23}
在 run
方法的簽章 (Signature) 中,我們可以 Type-Hint 任何需要的相依性。Laravel 的 Service Container 會自動解析 Type-Hint 中的相依性。
使用 Model Factory
當然,手動為每個要填入的 Model 指定屬性值是很麻煩的。我們不需要這麼做,而可以使用 Model Factory 來方便地產生大量資料。首先,請先看看 Model Factory 的說明文件以瞭解如何定義 Factory。
舉例來說,我們先來建立 50 個使用者,其中每個使用者都有 1 篇關聯的貼文:
1use App\Models\User;23/**4 * Run the database seeders.5 */6public function run(): void7{8 User::factory()9 ->count(50)10 ->hasPosts(1)11 ->create();12}
1use App\Models\User;23/**4 * Run the database seeders.5 */6public function run(): void7{8 User::factory()9 ->count(50)10 ->hasPosts(1)11 ->create();12}
呼叫其他 Seeder
在 DatabaseSeeder
類別中,我們可以使用 call
方法來執行其他 Seed 類別。使用 call
方法,我們就可以將資料填充的城市拆分成多個檔案,以避免單一 Seeder 類別過於肥大。call
方法接受一組要執行的 Seeder 類別名稱陣列:
1/**2 * Run the database seeders.3 */4public function run(): void5{6 $this->call([7 UserSeeder::class,8 PostSeeder::class,9 CommentSeeder::class,10 ]);11}
1/**2 * Run the database seeders.3 */4public function run(): void5{6 $this->call([7 UserSeeder::class,8 PostSeeder::class,9 CommentSeeder::class,10 ]);11}
靜音 Model Event
在進行資料填充時,我們可能會想讓 Model 不要分派 Event。若要防止 Model 分派 Event,可使用 WithoutModelEvent
Trait。使用 WithoutModelEvents
Trait 時,該 Trait 會確保 Model 不要分派 Event,且也會套用到使用 call
方法執行的 Seed 類別上:
1<?php23namespace Database\Seeders;45use Illuminate\Database\Seeder;6use Illuminate\Database\Console\Seeds\WithoutModelEvents;78class DatabaseSeeder extends Seeder9{10 use WithoutModelEvents;1112 /**13 * Run the database seeders.14 */15 public function run(): void16 {17 $this->call([18 UserSeeder::class,19 ]);20 }21}
1<?php23namespace Database\Seeders;45use Illuminate\Database\Seeder;6use Illuminate\Database\Console\Seeds\WithoutModelEvents;78class DatabaseSeeder extends Seeder9{10 use WithoutModelEvents;1112 /**13 * Run the database seeders.14 */15 public function run(): void16 {17 $this->call([18 UserSeeder::class,19 ]);20 }21}
執行 Seeder
我們可以執行 db:seed
Artisan 指令來填充資料庫。預設情況下,db:seed
指令會執行 Database\Seeders\DatabaseSeeder
類別,在該類別內可以進一步叫用其他 Seed 類別。不過,我們也可以使用 --class
選項來個別指定要執行的 Seeder 類別:
1php artisan db:seed23php artisan db:seed --class=UserSeeder
1php artisan db:seed23php artisan db:seed --class=UserSeeder
我們也可以使用 migrate:fresh
指令,並搭配 --seed
選項來填充資料。該指令會刪除所有資料表,並重新執行所有的 Migration。若有需要完全重建資料庫,就很適合使用這個指令。--seeder
選項可用來指定執行特定的 Seeder:
1php artisan migrate:fresh --seed23php artisan migrate:fresh --seed --seeder=UserSeeder
1php artisan migrate:fresh --seed23php artisan migrate:fresh --seed --seeder=UserSeeder
在正式環境中強制執行 Seeder
有些資料填充的動作是可能會導致資料被修改或消失。為了避免在正式環境資料庫中執行資料填充指令,因此在 production
環境中執行 Seeder 時,會出現提示要求確認。若要強制 Seeder 而不跳出提示,請使用 --force
旗標:
1php artisan db:seed --force
1php artisan db:seed --force