国产chinesehdxxxx野外,国产av无码专区亚洲av琪琪,播放男人添女人下边视频,成人国产精品一区二区免费看,chinese丰满人妻videos

Eloquent ORM ―― 關(guān)聯(lián)關(guān)系

2018-02-24 15:38 更新

Eloquent ORM —— 關(guān)聯(lián)關(guān)系

1、簡介

數(shù)據(jù)表經(jīng)常要與其它表做關(guān)聯(lián),比如一篇博客文章可能有很多評論,或者一個訂單會被關(guān)聯(lián)到下單用戶,Eloquent變得簡單,并且支持多種不同類型的關(guān)聯(lián)關(guān)系:

2、定義關(guān)聯(lián)關(guān)系

Eloquent關(guān)聯(lián)關(guān)系以Eloquent模型類方法的形式被定義。和Eloquent模型本身一樣,關(guān)聯(lián)關(guān)系也是強大的查詢構(gòu)建器,定義關(guān)聯(lián)關(guān)系為函數(shù)能夠提供功能強大的方法鏈和查詢能力。例如:

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

但是,在深入使用關(guān)聯(lián)關(guān)系之前,讓我們先學(xué)習(xí)如何定義每種關(guān)聯(lián)類型:

2.1?一對一

一對一關(guān)聯(lián)是一個非常簡單的關(guān)聯(lián)關(guān)系,例如,一個User模型有一個與之對應(yīng)的Phone模型。要定義這種模型,我們需要將phone方法置于User模型中,phone方法應(yīng)該返回Eloquent模型基類上hasOne方法的結(jié)果:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * 獲取關(guān)聯(lián)到用戶的手機
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

傳遞給hasOne方法的第一個參數(shù)是關(guān)聯(lián)模型的名稱,關(guān)聯(lián)關(guān)系被定義后,我們可以使用Eloquent的動態(tài)屬性獲取關(guān)聯(lián)記錄。動態(tài)屬性允許我們訪問關(guān)聯(lián)函數(shù)就像它們是定義在模型上的屬性一樣:

$phone = User::find(1)->phone;

Eloquent默認關(guān)聯(lián)關(guān)系的外鍵基于模型名稱,在本例中,Phone模型默認有一個user_id外鍵,如果你希望重寫這種約定,可以傳遞第二個參數(shù)到hasOne方法:

return $this->hasOne('App\Phone', 'foreign_key');

此外,Eloquent假設(shè)外鍵應(yīng)該在父級上有一個與之匹配的id,換句話說,Eloquent將會通過user表的id值去phone表中查詢user_id與之匹配的Phone記錄。如果你想要關(guān)聯(lián)關(guān)系使用其他值而不是id,可以傳遞第三個參數(shù)到hasOne來指定自定義的主鍵:

return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

2.1.1 定義相對的關(guān)聯(lián)

我們可以從User中訪問Phone模型,相應(yīng)的,我們也可以在Phone模型中定義關(guān)聯(lián)關(guān)系從而讓我們可以擁有該phoneUser。我們可以使用belongsTo方法定義與hasOne關(guān)聯(lián)關(guān)系相對的關(guān)聯(lián):

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model{
    /**
     * 獲取手機對應(yīng)的用戶
     */
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

在上面的例子中,Eloquent將會嘗試通過Phone模型的user_idUser模型查找與之匹配的記錄。Eloquent通過關(guān)聯(lián)關(guān)系方法名并在方法名后加_id后綴來生成默認的外鍵名。然而,如果Phone模型上的外鍵不是user_id,也可以將自定義的鍵名作為第二個參數(shù)傳遞到belongsTo方法:

/**
 * 獲取手機對應(yīng)的用戶
 */
public function user(){
    return $this->belongsTo('App\User', 'foreign_key');
}

如果父模型不使用id作為主鍵,或者你希望使用別的列來連接子模型,可以將父表自定義鍵作為第三個參數(shù)傳遞給belongsTo方法:

/**
 * 獲取手機對應(yīng)的用戶
 */
public function user(){
    return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}

2.2?一對多

“一對多”是用于定義單個模型擁有多個其它模型的關(guān)聯(lián)關(guān)系。例如,一篇博客文章?lián)碛袩o數(shù)評論,和其他關(guān)聯(lián)關(guān)系一樣,一對多關(guān)聯(lián)通過在Eloquent模型中定義方法來定義:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model{
    /**
     * 獲取博客文章的評論
     */
    public function comments()
    {
        return $this->hasMany('App\Comment');
    }
}

記住,Eloquent會自動判斷Comment模型的外鍵,為方便起見,Eloquent將擁有者模型名稱加上id后綴作為外鍵。因此,在本例中,Eloquent假設(shè)Comment模型上的外鍵是post_id

關(guān)聯(lián)關(guān)系被定義后,我們就可以通過訪問comments屬性來訪問評論集合。記住,由于Eloquent提供“動態(tài)屬性”,我們可以像訪問模型的屬性一樣訪問關(guān)聯(lián)方法:

$comments = App\Post::find(1)->comments;

foreach ($comments as $comment) {
    //
}

當然,由于所有關(guān)聯(lián)同時也是查詢構(gòu)建器,我們可以添加更多的條件約束到通過調(diào)用comments方法獲取到的評論上:

$comments = App\Post::find(1)->comments()->where('title', 'foo')->first();

hasOne方法一樣,你還可以通過傳遞額外參數(shù)到hasMany方法來重新設(shè)置外鍵和本地主鍵:

return $this->hasMany('App\Comment', 'foreign_key');
return $this->hasMany('App\Comment', 'foreign_key', 'local_key');

2.2.1 定義相對的關(guān)聯(lián)

現(xiàn)在我們可以訪問文章的所有評論了,接下來讓我們定義一個關(guān)聯(lián)關(guān)系允許通過評論訪問所屬文章。要定義與hasMany相對的關(guān)聯(lián)關(guān)系,需要在子模型中定義一個關(guān)聯(lián)方法去調(diào)用belongsTo方法:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model{
    /**
     * 獲取評論對應(yīng)的博客文章
     */
    public function post()
    {
        return $this->belongsTo('App\Post');
    }
}

關(guān)聯(lián)關(guān)系定義好之后,我們可以通過訪問動態(tài)屬性post來獲取一條Comment對應(yīng)的Post

$comment = App\Comment::find(1);
echo $comment->post->title;

在上面這個例子中,Eloquent嘗試匹配Comment模型的post_idPost模型的id,Eloquent通過關(guān)聯(lián)方法名加上_id后綴生成默認外鍵,當然,你也可以通過傳遞自定義外鍵名作為第二個參數(shù)傳遞到belongsTo方法,如果你的外鍵不是post_id,或者你想自定義的話:

/**
 * 獲取評論對應(yīng)的博客文章
 */
public function post(){
    return $this->belongsTo('App\Post', 'foreign_key');
}

如果你的父模型不使用id作為主鍵,或者你希望通過其他列來連接子模型,可以將自定義鍵名作為第三個參數(shù)傳遞給belongsTo方法:

/**
 * 獲取評論對應(yīng)的博客文章
 */
public function post(){
    return $this->belongsTo('App\Post', 'foreign_key', 'other_key');
}

2.3?多對多

多對多關(guān)系比hasOnehasMany關(guān)聯(lián)關(guān)系要稍微復(fù)雜一些。這種關(guān)聯(lián)關(guān)系的一個例子就是一個用戶有多個角色,同時一個角色被多個用戶共用。例如,很多用戶可能都有一個“Admin”角色。要定義這樣的關(guān)聯(lián)關(guān)系,需要三個數(shù)據(jù)表:usersrolesrole_user,role_user表按照關(guān)聯(lián)模型名的字母順序命名,并且包含user_idrole_id兩個列。

多對多關(guān)聯(lián)通過編寫一個調(diào)用Eloquent基類上的belongsToMany方法的函數(shù)來定義:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * 用戶角色
     */
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
}

關(guān)聯(lián)關(guān)系被定義之后,可以使用動態(tài)屬性roles來訪問用戶的角色:

$user = App\User::find(1);

foreach ($user->roles as $role) {
    //
}

當然,和所有其它關(guān)聯(lián)關(guān)系類型一樣,你可以調(diào)用roles方法來添加條件約束到關(guān)聯(lián)查詢上:

$roles = App\User::find(1)->roles()->orderBy('name')->get();

正如前面所提到的,為了決定關(guān)聯(lián)關(guān)系連接表的表名,Eloquent以字母順序連接兩個關(guān)聯(lián)模型的名字。然而,你可以重寫這種約定——通過傳遞第二個參數(shù)到belongsToMany方法:

return $this->belongsToMany('App\Role', 'user_roles');

除了自定義連接表的表名,你還可以通過傳遞額外參數(shù)到belongsToMany方法來自定義該表中字段的列名。第三個參數(shù)是你定義的關(guān)系模型的外鍵名稱,第四個參數(shù)你要連接到的模型的外鍵名稱:

return $this->belongsToMany('App\Role', 'user_roles', 'user_id', 'role_id');

2.3.1 定義相對的關(guān)聯(lián)關(guān)系

要定義與多對多關(guān)聯(lián)相對的關(guān)聯(lián)關(guān)系,只需在關(guān)聯(lián)模型中在調(diào)用一下belongsToMany方法即可。讓我們在Role模型中定義users方法:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Role extends Model{
    /**
     * 角色用戶
     */
    public function users()
    {
        return $this->belongsToMany('App\User');
    }
}

正如你所看到的,定義的關(guān)聯(lián)關(guān)系和與其對應(yīng)的User中定義的一模一樣,只是前者引用App\Role,后者引用App\User,由于我們再次使用了belongsToMany方法,所有的常用表和鍵自定義選項在定義與多對多相對的關(guān)聯(lián)關(guān)系時都是可用的。

2.3.2 獲取中間表的列

正如你已經(jīng)學(xué)習(xí)到的,處理多對多關(guān)聯(lián)要求一個中間表。Eloquent提供了一些有用的方法來與其進行交互,例如,我們假設(shè)User對象有很多與之關(guān)聯(lián)的Role對象,訪問這些關(guān)聯(lián)關(guān)系之后,我們可以使用模型上的pivot屬性訪問中間表:

$user = App\User::find(1);

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}

注意我們獲取到的每一個Role模型都被自動賦上了pivot屬性。該屬性包含一個代表中間表的模型,并且可以像其它Eloquent模型一樣使用。

默認情況下,只有模型鍵才能用在privot對象上,如果你的privot表包含額外的屬性,必須在定義關(guān)聯(lián)關(guān)系時進行指定:

return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');

如果你想要你的privot表自動包含created_atupdated_at時間戳,在關(guān)聯(lián)關(guān)系定義時使用withTimestamps方法:

return $this->belongsToMany('App\Role')->withTimestamps();

2.4 遠層的一對多

“遠層一對多”關(guān)聯(lián)為通過中間關(guān)聯(lián)訪問遠層的關(guān)聯(lián)關(guān)系提供了一個便利之道。例如,Country模型通過中間的User模型可能擁有多個Post模型。在這個例子中,你可以輕易的聚合給定國家的所有文章,讓我們看看定義這個關(guān)聯(lián)關(guān)系需要哪些表:

countries
    id - integer
    name - string

users
    id - integer
    country_id - integer
    name - string

posts
    id - integer
    user_id - integer
    title - string

盡管posts表不包含country_id列,hasManyThrough關(guān)聯(lián)提供了通過$country->posts來訪問一個國家的所有文章。要執(zhí)行該查詢,Eloquent在中間表$users上檢查country_id,查找到相匹配的用戶ID后,通過用戶ID來查詢posts表。

既然我們已經(jīng)查看了該關(guān)聯(lián)關(guān)系的數(shù)據(jù)表結(jié)構(gòu),接下來讓我們在Country模型上進行定義:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Country extends Model{
    /**
     * 獲取指定國家的所有文章
     */
    public function posts()
    {
        return $this->hasManyThrough('App\Post', 'App\User');
    }
}

第一個傳遞到hasManyThrough方法的參數(shù)是最終我們希望訪問的模型的名稱,第二個參數(shù)是中間模型名稱。

當執(zhí)行這種關(guān)聯(lián)查詢時通常Eloquent外鍵規(guī)則會被使用,如果你想要自定義該關(guān)聯(lián)關(guān)系的外鍵,可以將它們作為第三個、第四個參數(shù)傳遞給hasManyThrough方法。第三個參數(shù)是中間模型的外鍵名,第四個參數(shù)是最終模型的外鍵名。

class Country extends Model{
    public function posts()
    {
        return $this->hasManyThrough('App\Post', 'App\User', 'country_id', 'user_id');
    }
}

2.5 多態(tài)關(guān)聯(lián)

2.5.1?表結(jié)構(gòu)

多態(tài)關(guān)聯(lián)允許一個模型在單個關(guān)聯(lián)下屬于多個不同模型。例如,假如你想要為產(chǎn)品和職工存儲照片,使用多態(tài)關(guān)聯(lián),你可以在這兩種場景下使用單個photos表,首先,讓我們看看構(gòu)建這種關(guān)聯(lián)關(guān)系需要的表結(jié)構(gòu):

staff
    id - integer
    name - string

products
    id - integer
    price - integer

photos
    id - integer
    path - string
    imageable_id - integer
    imageable_type - string

兩個重要的列需要注意的是photos表上的imageable_idimageable_type。imageable_id列包含staffproduct的ID值,而imageable_type列包含所屬模型的類名。當訪問imageable關(guān)聯(lián)時,ORM根據(jù)imageable_type列來判斷所屬模型的類型并返回相應(yīng)模型實例。

2.5.2 ?模型結(jié)構(gòu)

接下來,讓我們看看構(gòu)建這種關(guān)聯(lián)關(guān)系需要在模型中定義什么:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Photo extends Model{
    /**
     * 獲取所有擁有的imageable模型
     */
    public function imageable()
    {
        return $this->morphTo();
    }
}

class Staff extends Model{
    /**
     * 獲取所有職員照片
     */
    public function photos()
    {
        return $this->morphMany('App\Photo', 'imageable');
    }
}

class Product extends Model{
    /**
     * 獲取所有產(chǎn)品照片
     */
    public function photos()
    {
        return $this->morphMany('App\Photo', 'imageable');
    }
}

2.5.3 獲取多態(tài)關(guān)聯(lián)

數(shù)據(jù)表和模型定義好以后,可以通過模型訪問關(guān)聯(lián)關(guān)系。例如,要訪問一個職員的所有照片,可以通過使用photos的動態(tài)屬性:

$staff = App\Staff::find(1);

foreach ($staff->photos as $photo) {
    //
}

你還可以通過訪問調(diào)用morphTo方法名來從多態(tài)模型中獲取多態(tài)關(guān)聯(lián)的所屬對象。在本例中,就是Photo模型中的imageable方法。因此,我們可以用動態(tài)屬性的方式訪問該方法:

$photo = App\Photo::find(1);
$imageable = $photo->imageable;

Photo模型上的imageable關(guān)聯(lián)返回StaffProduct實例,這取決于那個類型的模型擁有該照片。

2.6 多對多多態(tài)關(guān)聯(lián)

2.6.1 表結(jié)構(gòu)

除了傳統(tǒng)的多態(tài)關(guān)聯(lián),還可以定義“多對多”的多態(tài)關(guān)聯(lián),例如,一個博客的PostVideo模型可能共享一個Tag模型的多態(tài)關(guān)聯(lián)。使用對多對的多態(tài)關(guān)聯(lián)允許你在博客文章和視頻之間有唯一的標簽列表。首先,讓我們看看表結(jié)構(gòu):

posts
    id - integer
    name - string

videos
    id - integer
    name - string

tags
    id - integer
    name - string

taggables
    tag_id - integer
    taggable_id - integer
    taggable_type - string

2.6.2 模型結(jié)構(gòu)

接下來,我們準備在模型中定義該關(guān)聯(lián)關(guān)系。PostVideo模型都有一個tags方法調(diào)用Eloquent基類的morphToMany方法:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model{
    /**
     * 獲取指定文章所有標簽
     */
    public function tags()
    {
        return $this->morphToMany('App\Tag', 'taggable');
    }
}

2.6.3 定義相對的關(guān)聯(lián)關(guān)系

接下來,在Tag模型中,應(yīng)該為每一個關(guān)聯(lián)模型定義一個方法,例如,我們定義一個posts方法和videos方法:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model{
    /**
     * 獲取所有分配該標簽的文章
     */
    public function posts()
    {
        return $this->morphedByMany('App\Post', 'taggable');
    }

    /**
     * 獲取分配該標簽的所有視頻
     */
    public function videos()
    {
        return $this->morphedByMany('App\Video', 'taggable');
    }
}

2.6.4 獲取關(guān)聯(lián)關(guān)系

定義好數(shù)據(jù)庫和模型后可以通過模型訪問關(guān)聯(lián)關(guān)系。例如,要訪問一篇文章的所有標簽,可以使用動態(tài)屬性tags

$post = App\Post::find(1);

foreach ($post->tags as $tag) {
    //
}

還可以通過訪問調(diào)用morphedByMany的方法名從多態(tài)模型中獲取多態(tài)關(guān)聯(lián)的所屬對象。在本例中,就是Tag模型中的posts或者videos方法:

$tag = App\Tag::find(1);

foreach ($tag->videos as $video) {
    //
}

3、關(guān)聯(lián)查詢

由于Eloquent所有關(guān)聯(lián)關(guān)系都是通過函數(shù)定義,你可以調(diào)用這些方法來獲取關(guān)聯(lián)關(guān)系的實例而不需要再去手動執(zhí)行關(guān)聯(lián)查詢。此外,所有Eloquent關(guān)聯(lián)關(guān)系類型同時也是查詢構(gòu)建器,允許你在最終在數(shù)據(jù)庫執(zhí)行SQL之前繼續(xù)添加條件約束到關(guān)聯(lián)查詢上。

例如,假定在一個博客系統(tǒng)中一個User模型有很多相關(guān)的Post模型:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model{
    /**
     * 獲取指定用戶的所有文章
     */
    public function posts()
    {
        return $this->hasMany('App\Post');
    }
}

你可以像這樣查詢posts關(guān)聯(lián)并添加額外的條件約束到該關(guān)聯(lián)關(guān)系上:

$user = App\User::find(1);
$user->posts()->where('active', 1)->get();

你可以在關(guān)聯(lián)關(guān)系上使用任何查詢構(gòu)建器!

關(guān)聯(lián)關(guān)系方法 VS 動態(tài)屬性

如果你不需要添加額外的條件約束到Eloquent關(guān)聯(lián)查詢,你可以簡單通過動態(tài)屬性來訪問關(guān)聯(lián)對象,例如,還是拿UserPost模型作為例子,你可以像這樣訪問所有用戶的文章:

$user = App\User::find(1);

foreach ($user->posts as $post) {
    //
}

動態(tài)屬性就是”懶惰式加載來預(yù)加載他們知道在加載模型時要被訪問的關(guān)聯(lián)關(guān)系。渴求式加載有效減少了必須要被執(zhí)以加載模型關(guān)聯(lián)的SQL查詢。

查詢已存在的關(guān)聯(lián)關(guān)系

訪問一個模型的記錄的時候,你可能希望基于關(guān)聯(lián)關(guān)系是否存在來限制查詢結(jié)果的數(shù)目。例如,假設(shè)你想要獲取所有至少有一個評論的博客文章,要實現(xiàn)這個,可以傳遞關(guān)聯(lián)關(guān)系的名稱到has方法:

// 獲取所有至少有一條評論的文章...
$posts = App\Post::has('comments')->get();

你還可以指定操作符和大小來自定義查詢:

// 獲取所有至少有三條評論的文章...
$posts = Post::has('comments', '>=', 3)->get();

還可以使用”.“來構(gòu)造嵌套has語句,例如,你要獲取所有至少有一條評論及投票的所有文章:

// 獲取所有至少有一條評論獲得投票的文章...
$posts = Post::has('comments.votes')->get();

如果你需要更強大的功能,可以使用whereHasorWhereHas方法將where條件放到has查詢上,這些方法允許你添加自定義條件約束到關(guān)聯(lián)關(guān)系條件約束,例如檢查一條評論的內(nèi)容:

// 獲取所有至少有一條評論包含foo字樣的文章
$posts = Post::whereHas('comments', function ($query) {
    $query->where('content', 'like', 'foo%');
})->get();

3.1 渴求式加載

當以屬性方式訪問數(shù)據(jù)庫關(guān)聯(lián)關(guān)系的時候,關(guān)聯(lián)關(guān)系數(shù)據(jù)時”懶惰式加載“的,這意味著關(guān)聯(lián)關(guān)系數(shù)據(jù)直到第一次訪問的時候才被加載。然而,Eloquent可以在查詢父級模型的同時”渴求式加載“關(guān)聯(lián)關(guān)系。渴求式加載緩解了N+1查詢問題,要闡明N+1查詢問題,考慮下關(guān)聯(lián)到AuthorBook模型:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model{
    /**
     * 獲取寫這本書的作者
     */
    public function author()
    {
        return $this->belongsTo('App\Author');
    }
}

現(xiàn)在,讓我們獲取所有書及其作者:

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

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

該循環(huán)先執(zhí)行1次查詢獲取表中的所有書,然后另一個查詢獲取每一本書的作者,因此,如果有25本書,要執(zhí)行26次查詢:1次是獲取書本身,剩下的25次查詢是為每一本書獲取其作者。

謝天謝地,我們可以使用渴求式加載來減少該操作到2次查詢。當查詢的時候,可以使用with方法指定應(yīng)該被渴求式加載的關(guān)聯(lián)關(guān)系:

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

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

在該操作中,只執(zhí)行兩次查詢即可:

select * from books
select * from authors where id in (1, 2, 3, 4, 5, ...)

3.1.1 渴求式加載多個關(guān)聯(lián)關(guān)系

有時候你需要在單個操作中渴求式加載幾個不同的關(guān)聯(lián)關(guān)系。要實現(xiàn)這個,只需要添加額外的參數(shù)到with方法即可:

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

3.1.2 嵌套的渴求式加載

要渴求式加載嵌套的關(guān)聯(lián)關(guān)系,可以使用”.“語法。例如,讓我們在一個Eloquent語句中渴求式加載所有書的作者及所有作者的個人聯(lián)系方式:

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

3.2 帶條件約束的渴求式加載

有時候我們希望渴求式加載一個關(guān)聯(lián)關(guān)系,但還想為渴求式加載指定更多的查詢條件:

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

在這個例子中,Eloquent只渴求式加載title包含first的文章。當然,你可以調(diào)用其它查詢構(gòu)建器來自定義渴求式加載操作:

$users = App\User::with(['posts' => function ($query) {
    $query->orderBy('created_at', 'desc');
}])->get();

3.3 懶惰渴求式加載

有時候你需要在父模型已經(jīng)被獲取后渴求式加載一個關(guān)聯(lián)關(guān)系。例如,這在你需要動態(tài)決定是否加載關(guān)聯(lián)模型時可能很有用:

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

if ($someCondition) {
    $books->load('author', 'publisher');
}

如果你需要設(shè)置更多的查詢條件到渴求式加載查詢上,可以傳遞一個閉包到load方法:

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

4、插入關(guān)聯(lián)模型

4.1 基本使用

4.1.1 save方法

Eloquent提供了便利的方法來添加新模型到關(guān)聯(lián)關(guān)系。例如,也許你需要插入新的CommentPost模型,你可以從關(guān)聯(lián)關(guān)系的save方法直接插入Comment而不是手動設(shè)置Commentpost_id屬性:

$comment = new App\Comment(['message' => 'A new comment.']);
$post = App\Post::find(1);
$comment = $post->comments()->save($comment);

注意我們沒有用動態(tài)屬性方式訪問comments,而是調(diào)用comments方法獲取關(guān)聯(lián)關(guān)系實例。save方法會自動添加post_id值到新的Comment模型。

如果你需要保存多個關(guān)聯(lián)模型,可以使用saveMany方法:

$post = App\Post::find(1);

$post->comments()->saveMany([
    new App\Comment(['message' => 'A new comment.']),
    new App\Comment(['message' => 'Another comment.']),
]);

4.1.2 save & 多對多關(guān)聯(lián)

當處理多對多關(guān)聯(lián)的時候,save方法以數(shù)組形式接收額外的中間表屬性作為第二個參數(shù):

App\User::find(1)->roles()->save($role, ['expires' => $expires]);

4.1.3 create方法

除了savesaveMany方法外,還可以使用create方法,該方法接收屬性數(shù)組、創(chuàng)建模型、然后插入數(shù)據(jù)庫。savecreate的不同之處在于save接收整個Eloquent模型實例而create接收原生PHP數(shù)組:

$post = App\Post::find(1);

$comment = $post->comments()->create([
    'message' => 'A new comment.',
]);

使用create方法之前確保先瀏覽屬性批量賦值文檔。

4.1.4 更新”屬于“關(guān)聯(lián)

更新belongsTo關(guān)聯(lián)的時候,可以使用associate方法,該方法會在子模型設(shè)置外鍵:

$account = App\Account::find(10);
$user->account()->associate($account);
$user->save();

移除belongsTo關(guān)聯(lián)的時候,可以使用dissociate方法。該方法在子模型上取消外鍵和關(guān)聯(lián):

$user->account()->dissociate();
$user->save();

4.2 多對多關(guān)聯(lián)

4.2.1 附加/分離

處理多對多關(guān)聯(lián)的時候,Eloquent提供了一些額外的幫助函數(shù)來使得處理關(guān)聯(lián)模型變得更加方便。例如,讓我們假定一個用戶可能有多個角色同時一個角色屬于多個用戶,要通過在連接模型的中間表中插入記錄附加角色到用戶上,可以使用attach方法:

$user = App\User::find(1);
$user->roles()->attach($roleId);

附加關(guān)聯(lián)關(guān)系到模型,還可以以數(shù)組形式傳遞額外被插入數(shù)據(jù)到中間表:

$user->roles()->attach($roleId, ['expires' => $expires]);

當然,有時候有必要從用戶中移除角色,要移除一個多對多關(guān)聯(lián)記錄,使用detach方法。detach方法將會從中間表中移除相應(yīng)的記錄;然而,兩個模型在數(shù)據(jù)庫中都保持不變:

// 從指定用戶中移除角色...
$user->roles()->detach($roleId);
// 從指定用戶移除所有角色...
$user->roles()->detach();

為了方便,attachdetach還接收數(shù)組形式的ID作為輸入:

$user = App\User::find(1);
$user->roles()->detach([1, 2, 3]);
$user->roles()->attach([1 => ['expires' => $expires], 2, 3]);

4.2.2 同步

你還可以使用sync方法構(gòu)建多對多關(guān)聯(lián)。sync方法接收數(shù)組形式的ID并將其放置到中間表。任何不在該數(shù)組中的ID對應(yīng)記錄將會從中間表中移除。因此,該操作完成后,只有在數(shù)組中的ID對應(yīng)記錄還存在于中間表:

$user->roles()->sync([1, 2, 3]);

你還可以和ID一起傳遞額外的中間表值:

$user->roles()->sync([1 => ['expires' => true], 2, 3]);

4.3 觸發(fā)父級時間戳

當一個模型屬于另外一個時,例如Comment屬于Post,子模型更新時父模型的時間戳也被更新將很有用,例如,當Comment模型被更新時,你可能想要”觸發(fā)“創(chuàng)建其所屬模型Postupdated_at時間戳。Eloquent使得這項操作變得簡單,只需要添加包含關(guān)聯(lián)關(guān)系名稱的touches屬性到子模型中即可:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model{
    /**
     * 要觸發(fā)的所有關(guān)聯(lián)關(guān)系
     *
     * @var array
     */
    protected $touches = ['post'];

    /**
     * 評論所屬文章
     */
    public function post()
    {
        return $this->belongsTo('App\Post');
    }
}

現(xiàn)在,當你更新Comment時,所屬模型Post將也會更新其updated_at值:

$comment = App\Comment::find(1);
$comment->text = 'Edit to this comment!';
$comment->save();

擴展閱讀1:實例教程 ——?關(guān)聯(lián)關(guān)系及其在模型中的定義(一)

擴展閱讀2:實例教程 —— 關(guān)聯(lián)關(guān)系及其在模型中的定義(二)

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號