Laravel 5.1 文檔攻略——Laravel Eloquent ORM最強大也是最難理解的部分:數據關係

簡介

其實你們都知道,數據表之間都是能夠關聯的,Eloquent ORM是數據模型操做代替表操做,那麼表的關聯查詢,在Eloquent這裏也就是模型間的關聯查詢,這就是本章的主要內容;laravel

Eloquent一個支持如下6種表間關係:sql

  • One To One(一對一)數據庫

  • One To Many(一對多)數組

  • Many To Many(多對多)性能優化

  • Has Many Through(跨表一對多)閉包

  • Polymorphic Relations(belongsTo多態)post

  • Many To Many Polymorphic Relations(belongsToMany多態)性能

前三個關係是什麼就很少解釋了(請自行百度),這個地方須要不少耐心,努力讓本身習慣對象思惟,暫時先不要用sql,練一段時間就會發現很是好用;優化

固然,也有人吐槽Eloquent因爲過於強大,形成每次加載都帶一大堆東西,影響效率(實際沒啥影響,不服的拿數據跟我說),可是在代碼的編寫效率,可讀性,可維護性上能夠說是質的飛躍,因此仍是強烈建議優先使用。this

這一章我是學得最先,可是教程是寫的最晚的,由於各類關係比較複雜,好在我是作產品出身,應該能夠把複雜的事情解釋清楚,下面就讓咱們來認識一下這個星球上最強大的ORM:Eloquent

基本概念

先看看是怎麼使用的吧:

$user->posts()->where('active', 1)->get();

這個就是經過$user對象查出他一共發佈了多少篇文章(狀態爲已發佈的)。

咱們看到posts()在這裏是 $user 的一個方法,因此要使用關聯查詢,得先在$user模型裏定義關係(方法);

一對一

\oneToOne.png

從這張圖中,咱們能夠看到要使用Eloquent 模型關係,第一步要在模型裏定義模型關係,第二步數據庫要準備正確的表;第三部分使用 查詢的方法,第四部分是使用綁定和解除綁定的方法,咱們後續的模型關係都按照這個流程理解和解釋;

要點:反覆觀察圖!

定義模型

定義User模型

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

定義Phone模型

namespace App;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model
{

    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

注意:定義模型的時候方法名注意單複數,「一」就用單數,「多」就用複數,這樣不容易混淆搞錯。hasOne() 相似這個關係綁定方法有不少,須要在使用中慢慢熟悉,注意觀察。

數據表

主要是注意,外鍵和中間表這些東西,本例中沒有中間表;

關係查詢

模型關係方法查詢

$user->posts()->where('active', 1)->get();

這就是模型方法查詢,$user->posts() 這裏查出來是個DQB對象,後面能夠接各類數據庫查詢方法;

動態屬性查詢

$user->posts;

你能夠把關係當作屬性用,直接查出來一個collection集;缺點是後面不能跟DQB方法了。

這兩種方法都很經常使用,酌情使用;(下同,再也不解釋)

關係綁定和解除

通用的綁定方法就是save();

通用的解除方法,對於belongsTo的關係是dissociate(); 對於belongsToMany的關係是detach();

還有一些特定的綁定解除方法,咱們再單獨的關係模型中講;

一對多

\OneToMany.png

反綁

若是你要經過belongsTo關係綁定,能夠用associate()來綁定,最後要save()一下,如圖;

多對多

\manyToMany.png

因爲belongsTo換成了belongsToMany, 因此對應的綁定方法換成了attach()和detach();注意這裏面填對象ID,能夠用數組形式批量綁定;

save()方法仍然適用與關係綁定;

對中間表的操做

因爲多對多關係多了一張中間表,Eloquent除了默認對這裏面的外鍵進行操做之外,還能夠對中間表的其餘字段進行操做,看示例:

App\User::find(1)->roles()->save($role, ['expires' => $expires]);
$user->roles()->attach($roleId, ['expires' => $expires]);
$user->roles()->attach([1 => ['expires' => $expires], 2, 3]);
$user->roles()->sync([1 => ['expires' => true], 2, 3]);

sync()方法

sync就是同步,意思是說中間表會同步成sync()裏面參數同樣,沒有寫在參數裏的都會移除,所以能夠用來解除綁定;

Has Many Through(跨表一對多)

\hasManyThrough.png

其實這只是一種快速查詢方法,看圖,原本能夠先經過Conuntry查User,而後經過User查Post,如今你能夠經過Country直接查Post;

一般Country和User,User和Post的表間關係都是事先創建好的,這個時候你再使用hasManyThrough;

Polymorphic Relations(belongsTo多態)

\morphTo.png

原本belongsTo只能屬於一種對象的,就像女友只能屬於男友;如今好了,女友不只能夠屬於男友,還能夠屬於乾爹了。

開玩笑的,最多見的應用仍是圖片,能夠屬於多種模型,看圖;

咱們發現這裏的動詞變成了morphTo(), morphMany();

先上一小段英語課,提高一下語感:

morph這個詞的意思是改變形態,簡稱變態;這個和變形金剛的那個transform是不同的,那個主要是改變形狀;

morphTo(), morphMany(); 其實就是belongsTo() 和 hasMany() 多態形式,多態就是不只擁有男票,還有乾爹,有點「變態」;

關於綁定和解綁

associate()不適用用於morphTo();因此只能單向的用save()綁定了;

關於解綁,dissociate()也不適用用於morphTo();因此,只能把Photo實例刪除!!刪除了就沒任何關係了(由於沒有中間表)

感受有點不是很天然的設計,不過目前調查下來狀況就是這樣;

Many To Many Polymorphic Relations(belongsToMany多態)

\morphToMany.png

這個最典型的應用就是標籤了,標籤要涉及多對多的關係,還涉及對應不一樣類型的模型的問題,因此就是belongsToMany+多態;

看圖,可綁定,可解綁;

Eager Loading(預加載)

這個問題很簡單,看個實例你就懂了:

$books = App\Book::all();

foreach ($books as $book) {
    echo $book->author->name;
}

萬一books有一萬本,那麼循環就要1萬次,每次循環,由於用了關聯查詢$book->author->name;,都會讀數據庫一次,意味着至少讀數據庫一萬次,數據庫哭了。

Eager Loading 就是讓數據庫讀取發生在循環以前:

$books = App\Book::with('author')->get();

foreach ($books as $book) {
    echo $book->author->name;
}

看,加了個神奇的with()後,全部數據在foreach前都讀出來了,後面循環的只是讀出來的數據,一共查詢數據庫2次!!

Eager Loading能夠極大的緩解數據庫查詢壓力,是性能優化的重要手段!

Eager Loading 多個關係

就是一次多加幾張關聯表而已;

$books = App\Book::with('author', 'publisher')->get();

嵌套 Eager Loading

$books = App\Book::with('author.contacts')->get();

把書的做者讀出來,順便把做者的聯繫方式讀出來。

有條件的 Eager Loading

上面說的是整張表整張表的讀出來,太土豪了,其實有時候咱們只須要表裏的部分記錄:

$users = App\User::with(['posts' => function ($query) {
    $query->where('title', 'like', '%first%');

}])->get();

這中閉包的寫法咱們講過屢次,就是加個條件而已;

Lazy Eager Loading

這標題難道不是自相矛盾嗎?又Lazy,又Eager?

哦,原來是在lazy的流程裏判斷需不須要eager loading一下:

$books = App\Book::all();

if ($someCondition) {
    $books->load('author', 'publisher');
}
$books->load(['author' => function ($query) {
    $query->orderBy('published_date', 'asc');
}]);

注意這個load(),這是對collection用的;

跨模型更新時間戳

簡單的來講,就是一條評論更新的時候,順便把文章的'updated_at'字段也更新了;

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
     * All of the relationships to be touched.
     *
     * @var array
     */
    protected $touches = ['post'];

    /**
     * Get the post that the comment belongs to.
     */
    public function post()
    {
        return $this->belongsTo('App\Post');
    }
}

設置$touches這個屬性;

而後你更新Comment的時候,就會把Post的'updated_at'字段也更新了;

更多內容請訪問:Laravel 5.1 文檔攻略

相關文章
相關標籤/搜索