1. 程式人生 > >深入理解 Laravel Eloquent(二)——模型間關係(關聯)

深入理解 Laravel Eloquent(二)——模型間關係(關聯)

Eloquent是什麼

Eloquent 是一個 ORM,全稱為 Object Relational Mapping,翻譯為 “物件關係對映”(如果只把它當成 Database Abstraction Layer 陣列庫抽象層那就太小看它了)。所謂 “物件”,就是本文所說的 “模型(Model)”;物件關係對映,即為模型間關係。中文文件: http://laravel-china.org/docs/eloquent#relationships

下面我們開始一個一個地學習。

一對一關係

顧名思義,這描述的是兩個模型之間一對一的關係。這種關係是不需要中間表的。

假如我們有兩個模型:User 和 Account,分別對應註冊使用者和消費者,他們是一對一的關係,那麼如果我們要使用 Eloquent 提供的一對一關係方法,表結構應該是這樣的:

user: id ... ... account_id

account: id ... ... user_id

假設我們需要在 User 模型中查詢對應的 Account 表的資訊,那麼程式碼應該是這樣的。 `/app/models/User.php`:

<?php

class User extends Eloquent {

  

  protected $table = 'users';

  public function hasOneAccount()

  {

      return $this->hasOne('Account', 'user_id', 'id');

  }

}

然後,當我們需要用到這種關係的時候,該如何使用呢?如下:

$account = User::find(10)->hasOneAccount;

此時得到的 `$account` 即為 `Account` 類的一個例項。


這裡最難的地方在於後面的兩個 foreign_key 和 local_key 的設定,大家可以就此記住:在 User 類中,無論 hasOne 誰,第二個引數都是 `user_id`,第三個引數一般都是 `id`。由於前面的 `find(10)` 已經鎖定了 id = 10,所以這段函式對應的 SQL 為: `select * from account where user_id=10`。


這段程式碼除了展示了一對一關係該如何使用之外,還傳達了三點資訊,也是我對於大家使用 Eloquent 時候的建議:

1. 每一個 Model 中都指定表名

2. has one account 這樣的關係寫成 `hasOneAccount()` 而不是簡單的 `account()`

3. 每次使用模型間關係的時候都寫全引數,不要省略

相應的,如果使用 belongsTo() 關係,應該這麼寫:

<?php

class Account extends Eloquent {

  protected $table = 'accounts';

  

  public function belongsToUser()

  {

    return $this->belongsTo('User', 'user_id', 'id');

  }

}

一對多關係

學會了前面使用一對一關係的基礎方法,後面的幾種關係就簡單多了。

我們引入一個新的Model:Pay,付款記錄。表結構應該是這樣的:

user: id ... ...

pay: id ... ... user_id

User 和 Pay 具有一對多關係,換句話說就是一個 User 可以有多個 Pay,這樣的話,只在 Pay 表中存在一個 `user_id` 欄位即可。 `/app/models/User.php`:

<?php

class User extends Eloquent {

  

  protected $table = 'users';

  public function hasManyPays()

  {

    return $this->hasMany('Pay', 'user_id', 'id');

  }

}

然後,當我們需要用到這種關係的時候,該如何使用呢?如下:

$accounts = User::find(10)->hasManyPays()->get();

此時得到的 `$accounts` 即為 `Illuminate\Database\Eloquent\Collection` 類的一個例項。大家應該也已經注意到了,這裡不是簡單的 `-> hasOneAccount` 而是 `->hasManyPays()->get()`,為什麼呢?因為這裡是 `hasMany`,操作的是一個物件集合。

相應的 belongsTo() 的用法跟上面一對一關係一樣:

<?php

class Pay extends Eloquent {

  protected $table = 'pays';

  

  public function belongsToUser()

  {

    return $this->belongsTo('User', 'user_id', 'id');

  }

}

多對多關係

多對多關係和之前的關係完全不一樣,因為多對多關係可能出現很多冗餘資料,用之前自帶的表存不下了。

我們定義兩個模型:Article 和 Tag,分別表示文章和標籤,他們是多對多的關係。表結構應該是這樣的:

article: id ... ...

tag: id ... ...

article_tag: article_id tag_id

在 Model 中使用:

<?php

class Tag extends Eloquent {

  protected $table = 'tags';

  

  public function belongsToManyArticle()

  {

    return $this->belongsToMany('Article', 'article_tag', 'tag_id', 'article_id');

  }

}

需要注意的是,第三個引數是本類的 id,第四個引數是第一個引數那個類的 id。

使用跟 hasMany 一樣:

$tagsWithArticles = Tag::take(10)->get()->belongsToManyArticle()->get();

這裡會得到一個非常複雜的物件,可以自行 `var_dump()`。跟大家說一個訣竅,`var_dump()` 以後,用 Chrome 右鍵 “檢視原始碼”,就可以看到非常整齊的物件/陣列展開了。

在這裡給大家展示一個少見用法(奇技淫巧):

public function parent_video()

{

    return $this->belongsToMany($this, 'video_hierarchy', 'video_id', 'video_parent_id');

}

public function children_video()

{

    return $this->belongsToMany($this, 'video_hierarchy', 'video_parent_id', 'video_id');

}

對,你沒有看錯,可以 belongsToMany 自己。

其他關係

Eloquent 還提供 “遠層一對多關聯”、“多型關聯” 和 “多型的多對多關聯” 這另外三種用法,經過上面的學習,我們已經掌握了 Eloquent 模型間關係的基本概念和使用方法,剩下的幾種不常用的方法就留到我們用到的時候再自己探索吧。

重要技巧:關係預載入

你也許已經發現了,在一對一關係中,如果我們需要一次性查詢出10個 User 並帶上對應的 Account 的話,那麼就需要給資料庫打 1 + 10 條 SQL,這樣效能是很差的。我們可以使用一個重要的特性,關係預載入:http://laravel-china.org/docs/eloquent#eager-loading

直接上程式碼:

$users = User::with('hasOneAccount')->take(10)->get()

這樣生成的 SQL 就是這個樣子的:

select * from account where id in (1, 2, 3, ... ...)

這樣 1 + 10 條 SQL 就變成了 1 + 1 條,效能大增。

轉自:https://lvwenhan.com/laravel/423.html