2021年11月22日

PHP Laravel 小知識:hasOne 跟 belongsTo 差別在哪裡?

hasOnebelongsTo 都是 Laravel Eloquent 所提供的方法,負責處理一對一的關係。

那一樣都是一對一,這兩個用法的差別在哪裡呢?簡單來說是這樣:

  • hasOne 指的是「擁有一個東西」,我擁有一個東西,我在它的身上貼上了我的名字。
  • belongsTo 指的是「屬於某個人」,我屬於別人,我被貼上了他的名字。

 

我們來看下面的範例,

假設我們有兩張 Table,分別是 userscars ,在 Laravel中,分別會對應到 UserCar 兩個 Model。

我們設定的關係是,每個人只能擁有一輛車,反過來說,每輛車只能被一個人擁有

User Model中,car method 使用 hasOne, 因為在 User Model 中,主體是 User

現在我們來解讀 car method return 的那段程式:

$this->hasOne(Car::class)

$this 在這邊指的是 user ,因此這行程式直接讀起來就是:User has one car,使用者擁有一輛車,應該還蠻直觀的吧!

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function car()
    {
        return $this->hasOne(Car::class);
    }
}

再來看 Car Modeluser method 使用 belongsTo ,因為是在 Car Model 中,主體是 Car ,因此user method 的語意是: Car belongs to (a) user,車子屬於一個使用者。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Car extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

從語意的層面來看,好像都蠻正常的,但一般來說,我們會有一個問題:既然都是一對一的用法,那為什麼不能兩個都用 hasOne 或是都用 belongsTo ,或是甚至反過來用呢?

這就是關鍵所在了,要回答這個問題就要回到開頭講的,

  • hasOne 指的是「有一個」,我有一個東西,我在它身上貼上了我的名字。
  • belongsTo 指的是「屬於某個人」,我屬於別人,我被貼上了他的名字。

重點是誰被貼上了名字

在資料庫領域中,被貼上名字這件事其實指的就是 foreign key, FK ,也就是外鍵,被貼上名字的東西,它的 Table 上會有一欄 foreign key ,用來記錄所屬者的 primary key, PK

因此,當 foreign key 在誰身上,就代表它被貼上名字,它是屬於某個人的,它就要使用 belongsTo 去找到主人,而另一方就要使用 hasOne 去找到他的東西。

這時我們再回看看 UserCar 的範例,可以看到Car 使用 belongsTo 去建立跟 User的關係,套用剛剛的討論,是 Car 被貼上了名字,因此是 cars 有一欄 foreign key 儲存了對應的 users table 的 primary key

補充:

Laravel 預設會使用 function 名稱及對應 table 的 primary key 來組成 foreign key 的名稱,所以在 Car 中,belongsTo 會預設使用 function name 的 userusers table 的primary key 也就是 id 組成 foreign key: user_id

反過來說,如果我們把 foreigin key 放在 users 上,也就是我們在 users table 上放了 car_id ,那關係就會反過來了。

會變成在 Car model 中使用 hasOne 去建立跟 User 的關係,而 User model 則會使用 belongsTo 去和 Car 建立關係。

雖然這個反例在語意上有點怪,不過主要是想說明 hasOnebelongsTo 與 foreigin key 的關係,大家可以根據實際的需求做調整。

結論

hasOnebelongsTo 如何區別?

就結果而言,只要 foreign key 在別人身上,那自己就是使用 hasOne,若 foregin key 在自己身上,那自己就使用 belongsTo

 

本篇為 PHP 及 Laravel 系列文 → 看更多 PHP 及 Laravel 文章

同場加映:Laravel 一對多關係解釋

參考

【Larave學習書籍】 Laravel 啟動與運行(第二版)