欄位名 | 說明 | 格式 | 包含備註內容 |
---|---|---|---|
id | ID | unsignedBigInteger | 自動遞增 |
type_id | 產品分類 | unsignedBigInteger | foreign 外鍵關聯 接受空值 預設值為空 |
product_name | 產品名稱 | varchar(255) | |
product_description | 產品描述 | text | |
price | 產品價錢 | unsignedInteger | |
created_at | 新建時間 | timestamp | |
updated_at | 更新時間 | timestamp |
在 Migration & 資料庫設計 的文章中,有先說 create_products_table.php
的 type_id 一開始先不做「包含備註內容」的部份,等到後續新增 types 表時再做。
因為我想先以最基礎的去介紹,接著到模型關聯時再做,可能會更好理解。
(菜雞仔如我,當時也是這樣理解起來的)
但我會建議如果一開始在規劃資料庫時,就很清楚知道哪些表需要做 foreign key 的話,可以調整步驟優先建立,之後如果有沒思考到的部份再進行調整,操作起來會比較流暢。
如果是我的步驟:
(這只是我自己的想法,每個人的操作可能不同XD)
要在已經執行過 migration 的 products 表中加入 foreign key。
php artisan make:migration add_foreign_key_to_products_table --table=products
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
// 加入外鍵關聯,當 type_id 被刪除時設定為 null
$table->foreignId('type_id')
->nullable() // 允許為空
->constrained()
->onDelete('set null')
->comment('產品分類');
});
}
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
// 先移除外鍵再移除欄位
$table->dropForeign(['type_id']);
});
}
是希望如果 types 表某個 id 被刪除時,所有引用此 id 的資料會將其 type_id 自動設定為 null,之後可再將其產品重新分配類別!
因此需求,所以也將 type_id 設定為可接受 null。
php artisan migrate
這樣就會成功在 products 表的 type_id 欄位加入外鍵關聯到 types 表,並且當 type 被刪除時,type_id 會被設為 null。
最重要的是不會影響原本 products 表中的資料。
模型關聯(Eloquent Relationships)就是指資料表之間的邏輯關係。
例如:
一個「產品」可能屬於某一個「類別」,而一個「類別」可能包含多個「產品」。
所以透過模型關聯,我們可以很方便地從資料庫中取出這些關聯資料,而不需要寫太多的 SQL 查詢。
以下整理 GPT 提供的範例及基本應用:
一個模型只能與另一個模型擁有唯一的關聯。
class User extends Model {
public function profile() {
return $this->hasOne(Profile::class);
}
}
$user = User::find(1);
$profile = $user->profile; // 取得該使用者的個人資料
一個模型可以擁有多個關聯的資料。
class Category extends Model {
public function products() {
return $this->hasMany(Product::class);
}
}
$category = Category::find(1);
$products = $category->products; // 取得該類別下的所有產品
這是「一對多」的反向關聯。例如:產品屬於某個類別。
class Product extends Model {
public function type() {
return $this->belongsTo(Type::class);
}
}
$product = Product::find(1);
$type = $product->type; // 取得該產品所屬的類別
當兩個模型之間可以有多個關聯時使用。
例如:學生可以選修多門課程,而課程也可以有多個學生。
class Student extends Model {
public function courses() {
return $this->belongsToMany(Course::class);
}
}
$student = Student::find(1);
$courses = $student->courses; // 取得該學生的所有課程
允許不同的模型共用同一個關聯模型。
例如:文章和影片都可以有評論。
class Comment extends Model {
public function commentable() {
return $this->morphTo();
}
}
$comment = Comment::find(1);
$commentable = $comment->commentable; // 這可以是文章或影片
當你訪問關聯資料時,它會自動執行查詢。
$product = Product::find(1);
$category = $product->category; // 這會在訪問 category 時執行查詢
使用 with() 方法可以預先載入關聯資料,避免多次查詢(N+1 查詢問題)。
$products = Product::with('category')->get(); // 一次性載入產品及其類別
命名關聯方法時,遵循單數或複數的規則。
例如:
這樣更符合直觀想法,可讀性更高。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Type extends Model
{
use HasFactory;
protected $fillable =[
'name',
'sort',
];
/**
* 取得類別的商品
*/
public function product() {
return $this->hasMany('App\Product', 'type_id', 'id');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
protected $fillable = [
'type_id',
'product_name',
'product_description',
'price',
];
/**
* 取得商品的類別
*/
public function type() {
return $this->belongsTo('App\Type');
}
}
以上請求皆測試成功!