2021年11月22日

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

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

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

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

 

我們來看下面的範例,

假設我們有兩張 Table,分別是 users 及 cars ,在 Laravel中,分別會對應到 User 及 Car 兩個 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 Model ,user 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 去找到他的東西。

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

補充:

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

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

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

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

結論

hasOne 跟 belongsTo 如何區別?

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

 

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

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

參考

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