iT邦幫忙

第 11 屆 iThome 鐵人賽

2

one to one

hasOne()

使用情境:一對一的關係
例如,從Score中取得某位student的分數:

scores

id score student_id
1 92 2
2 82 3
3 77 1
4 100 4
hasOne('related', 'foreignKey', 'localKey');

若只有給第一個參數,則預設會從第一個參數的model中找該model的id。
假如學生的id在scores這張表中的欄位名稱為'stuID',那麼第二個參數要加入'studID'

hasOne(Score::class, 'stuID')

Model Student

     function score(){
        return $this->hasOne(Score::class); //預設會去找scores.student_id
     }
    $studentWithScore = Student::with('score')->find($student_id);

belongsTo()

使用情境:一對一或一對多的關係
例如,一間餐廳只會有一位業者,要從Restaurant中取得該餐廳的業者資料:
restaurants

id name owner_id
1 Steak House 2
2 Salt&Pepper 3
3 Pastar 2
belongsTo('related', 'foreignKey', 'localKey');

Model Restaurant


    public function owner()
    {
        return $this->belongsTo(Owner::class); //預設會去找restaurants.owner_id
    }
 $restaurantWithOwner = Restaurant::with('owner')->find($restaurant_id);

one to many

hasMany()

hasMany('related', 'foreignKey', 'localKey');

使用情境:一對多的關係
例如,一間餐廳有許多食物,要從Restaurant中取得該餐廳中的所有食物:
foods

id name restaurant_id
1 cake 2
2 banana 3
3 fired rice 2
    public function foods()
    {
        return $this->hasMany(Food::class); //預設會去找foods.restaurant_id,再根據foods.id找到關聯的food資料
    }
$restaurantWithFoods = Restaurant::with('foods')->find($restaurant_id);

many to many

belongsToMany()

belongsToMany('related', 'table', 'foreignPivotKey', 'relatedPivotKey')

belongsToMany('和該model關聯的model類', 'pivot的表名', '該model在pivot表中的對應id', '與該model關聯的model在pivot表中的對應id')

情境一:user 訂閱 channel,一個user可以訂閱很多channels,一個channel也可以被很多個users訂閱
pivot:subscriptions 定義user和channel間的關係

id user_id channel_id
1 1 2
2 1 3
3 2 1
4 2 2
  1. 拿到1號user訂閱的所有channel

Model User

   public function subscriptChannel()
    {
        return $this->belongsToMany(Channel::class, 'subscriptions', 'user_id' ,'channel_id'); //會去subscriptions中找跟user_id對應到的channel_id,再根據channel_id找到關聯的channel資料
    }
  1. 拿到1號channel的所有訂閱者

Model Channel

    public function subscriptUser()
    {
        return $this->belongsToMany(User::class, 'subscriptions', 'channel_id', 'user_id');
    }

補充

另外,可以在Model下定義關聯的function時,同時把該表所關聯的另一張表的資料也拉出來,
例如:
Model Student

     function score()
     {
        return $this->hasOne(Score::class)->with('subject'); 
     }

常見錯誤

當你試圖用with()拿到關聯的資料時,報出下面這樣的錯誤訊息:

Call to a member function addEagerConstraints() on null

可能在Model的關聯function忘了加return

function user()
{
        return $this->hasMany(User::class);
}

function命名很重要!!

使用hasMany的function name應該要是複數的table名稱;
例如

 public function foods()
    {
        return $this->hasMany(Food::class); 
    }

而使用hasOne或belongsTo的function name應該要是單數的table名稱;
範例

     function score()
     {
        return $this->hasOne(Score::class); 
     }
 public function owner()
    {
        return $this->belongsTo(Owner::class);
    }

若不依照上述的規則命名,在使用ORM去找Model所關聯的表時,會找不到東西。

子查詢

子查詢可以幫助我們根據表1關聯的表2的欄位來進行資料的篩選。
例如,假設scores這張表存了每位學生的國文和數學成績:student_id、math、chinse三個欄位
目標示要找出國文成績大於70,同時數學成績大於80的同學
SQL原生指令:

select * from students where exists(select * from scores where (math > 80 and chinese > 70) and student_id = students.id );

Laravel ORM:

Student::whereHas('scores', function ($query) {
                $query
                    ->where('math', '>=', 80)
                    ->where('chinese', '>=', 70);
            })->get();

提醒各位讀者,我接下來的新文章不會在出現在鐵人賽系列文中,想繼續訂閱我的新文章的話建議直接追蹤我的帳號喔~


上一篇
Day 35 Laravel 實作 LINE Bot 小幫手筆記
系列文
後端基礎PHP+Mysql & Laravel 30日養成計畫36
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
mlck970677
iT邦新手 5 級 ‧ 2020-02-18 16:17:05

DAY36喔!之後在拜讀 ~

我要留言

立即登入留言