摘要:關聯關系查詢在中,所有的關系都是使用函數定義的,可以在不執行關聯查詢的情況下獲取關聯的實例。
關聯關系 One To One
假設User模型關聯了Phone模型,要定義這樣一個關聯,需要在User模型中定義一個phone方法,該方法返回一個hasOne方法定義的關聯
hasOne("AppPhone"); } }
hasOne方法的第一個參數為要關聯的模型,定義好之后,可以使用下列語法查詢到關聯屬性了
$phone = User::find(1)->phone;
Eloquent會假定關聯的外鍵是基于模型名稱的,因此Phone模型會自動使用user_id字段作為外鍵,可以使用第二個參數和第三個參數覆蓋
return $this->hasOne("AppPhone", "foreign_key"); return $this->hasOne("AppPhone", "foreign_key", "local_key");定義反向關系
定義上述的模型之后,就可以使用User模型獲取Phone模型了,當然也可以通過Phone模型獲取所屬的User了,這就用到了belongsTo方法了
belongsTo("AppUser"); // return $this->belongsTo("AppUser", "foreign_key"); // return $this->belongsTo("AppUser", "foreign_key", "other_key"); } }One To Many
假設有一個帖子,它有很多關聯的評論信息,這種情況下應該使用一對多的關聯,使用hasMany方法
hasMany("AppComment"); } }
查詢操作
$comments = AppPost::find(1)->comments; foreach ($comments as $comment) { // } $comments = AppPost::find(1)->comments()->where("title", "foo")->first();定義反向關聯
反向關聯也是使用belongsTo方法,參考One To One部分。
$comment = AppComment::find(1); echo $comment->post->title;Many To Many
多對多關聯因為多了一個中間表,實現起來比hasOne和hasMany復雜一些。
考慮這樣一個場景,用戶可以屬于多個角色,一個角色也可以屬于多個用戶。這就引入了三個表: users, roles, role_user。其中role_user表為關聯表,包含兩個字段user_id和role_id。
多對多關聯需要使用belongsToMany方法
belongsToMany("AppRole", "role_user"); // 指定關聯表,關聯字段 // return $this->belongsToMany("AppRole", "role_user", "user_id", "role_id"); return $this->belongsToMany("AppRole"); } }
上述定義了一個用戶屬于多個角色,一旦該關系確立,就可以查詢了
$user = AppUser::find(1); foreach ($user->roles as $role) { // } $roles = AppUser::find(1)->roles()->orderBy("name")->get();反向關聯關系
反向關系與正向關系實現一樣
belongsToMany("AppUser"); } }檢索中間表的列值
對多對多關系來說,引入了一個中間表,因此需要有方法能夠查詢到中間表的列值,比如關系確立的時間等,使用pivot屬性查詢中間表
$user = AppUser::find(1); foreach ($user->roles as $role) { echo $role->pivot->created_at; }
上述代碼訪問了中間表的created_at字段。
注意的是,默認情況下之后模型的鍵可以通過pivot對象進行訪問,如果中間表包含了額外的屬性,在指定關聯關系的時候,需要使用withPivot方法明確的指定列名
return $this->belongsToMany("AppRole")->withPivot("column1", "column2");
如果希望中間表自動維護created_at和updated_at字段的話,需要使用withTimestamps()
return $this->belongsToMany("AppRole")->withTimestamps();Has Many Through
這種關系比較強大,假設這樣一個場景:Country模型下包含了多個User模型,而每個User模型又包含了多個Post模型,也就是說一個國家有很多用戶,而這些用戶都有很多帖子,我們希望查詢某個國家的所有帖子,怎么實現呢,這就用到了Has Many Through關系
countries id - integer name - string users id - integer country_id - integer name - string posts id - integer user_id - integer title - string
可以看到,posts表中并不直接包含country_id,但是它通過users表與countries表建立了關系
使用Has Many Through關系
namespace App; use IlluminateDatabaseEloquentModel; class Country extends Model { public function posts() { // return $this->hasManyThrough("AppPost", "AppUser", "country_id", "user_id"); return $this->hasManyThrough("AppPost", "AppUser"); } }
方法hasManyThrough的第一個參數是我們希望訪問的模型名稱,第二個參數是中間模型名稱。
HasManyThrough hasManyThrough( string $related, string $through, string|null $firstKey = null, string|null $secondKey = null, string|null $localKey = null )Polymorphic Relations (多態關聯)
多態關聯使得同一個模型使用一個關聯就可以屬于多個不同的模型,假設這樣一個場景,我們有一個帖子表和一個評論表,用戶既可以對帖子執行喜歡操作,也可以對評論執行喜歡操作,這樣的情況下該怎么處理呢?
表結構如下
posts id - integer title - string body - text comments id - integer post_id - integer body - text likes id - integer likeable_id - integer likeable_type - string
可以看到,我們使用likes表中的likeable_type字段判斷該記錄喜歡的是帖子還是評論,表結構有了,接下來就該定義模型了
morphTo(); } } class Post extends Model { public function likes() { return $this->morphMany("AppLike", "likeable"); } } class Comment extends Model { public function likes() { return $this->morphMany("AppLike", "likeable"); } }
默認情況下,likeable_type的類型是關聯的模型的完整名稱,比如這里就是AppPost和AppComment。
通常情況下我們可能會使用自定義的值標識關聯的表名,因此,這就需要自定義這個值了,我們需要在項目的服務提供者對象的boot方法中注冊關聯關系,比如AppServiceProvider的boot方法中
use IlluminateDatabaseEloquentRelationsRelation; Relation::morphMap([ "posts" => AppPost::class, "likes" => AppLike::class, ]);檢索多態關系
訪問一個帖子所有的喜歡
$post = AppPost::find(1); foreach ($post->likes as $like) { // }
訪問一個喜歡的帖子或者評論
$like = AppLike::find(1); $likeable = $like->likeable;
上面的例子中,返回的likeable會根據該記錄的類型返回帖子或者評論。
多對多的多態關聯多對多的關聯使用方法morphToMany和morphedByMany,這里就不多廢話了。
關聯關系查詢在Eloquent中,所有的關系都是使用函數定義的,可以在不執行關聯查詢的情況下獲取關聯的實例。假設我們有一個博客系統,User模型關聯了很多Post模型:
public function posts() { return $this->hasMany("AppPost"); }
你可以像下面這樣查詢關聯并且添加額外的約束
$user = AppUser::find(1); $user->posts()->where("active", 1)->get();
如果不需要對關聯的屬性添加約束,可以直接作為模型的屬性訪問,例如上面的例子,我們可以使用下面的方式訪問User的Post
$user = AppUser::find(1); foreach ($user->posts as $post) { // }
動態的屬性都是延遲加載的,它們只有在被訪問的時候才會去查詢數據庫,與之對應的是預加載,預加載可以使用關聯查詢出所有數據,減少執行sql的數量。
查詢關系存在性使用has方法可以基于關系的存在性返回結果
// 檢索至少有一個評論的所有帖子... $posts = AppPost::has("comments")->get(); // Retrieve all posts that have three or more comments... $posts = Post::has("comments", ">=", 3)->get(); // Retrieve all posts that have at least one comment with votes... $posts = Post::has("comments.votes")->get();
如果需要更加強大的功能,可以使用whereHas和orWhereHas方法,把where條件放到has語句中。
// 檢索所有至少存在一個匹配foo%的評論的帖子 $posts = Post::whereHas("comments", function ($query) { $query->where("content", "like", "foo%"); })->get();預加載
在訪問Eloquent模型的時候,默認情況下所有的關聯關系都是延遲加載的,在使用的時候才會開始加載,這就造成了需要執行大量的sql的問題,使用預加載功能可以使用關聯查詢出所有結果
belongsTo("AppAuthor"); } }
接下來我們檢索所有的書和他們的作者
$books = AppBook::all(); foreach ($books as $book) { echo $book->author->name; }
上面的查詢將會執行一個查詢查詢出所有的書,然后在遍歷的時候再執行N個查詢查詢出作者信息,顯然這樣做是非常低效的,幸好我們還有預加載功能,可以將這N+1個查詢減少到2個查詢,在查詢的時候,可以使用with方法指定哪個關系需要預加載。
$books = AppBook::with("author")->get(); foreach ($books as $book) { echo $book->author->name; }
對于該操作,會執行下列兩個sql
select * from books select * from authors where id in (1, 2, 3, 4, 5, ...)
預加載多個關系
$books = AppBook::with("author", "publisher")->get();
嵌套的預加載
$books = AppBook::with("author.contacts")->get();帶約束的預加載
$users = AppUser::with(["posts" => function ($query) { $query->where("title", "like", "%first%"); }])->get(); $users = AppUser::with(["posts" => function ($query) { $query->orderBy("created_at", "desc"); }])->get();延遲預加載
有時候,在上級模型已經檢索出來之后,可能會需要預加載關聯數據,可以使用load方法
$books = AppBook::all(); if ($someCondition) { $books->load("author", "publisher"); } $books->load(["author" => function ($query) { $query->orderBy("published_date", "asc"); }]);關聯模型插入 save方法
保存單個關聯模型
$comment = new AppComment(["message" => "A new comment."]); $post = AppPost::find(1); $post->comments()->save($comment);
保存多個關聯模型
$post = AppPost::find(1); $post->comments()->saveMany([ new AppComment(["message" => "A new comment."]), new AppComment(["message" => "Another comment."]), ]);save方法和多對多關聯
多對多關聯可以為save的第二個參數指定關聯表中的屬性
AppUser::find(1)->roles()->save($role, ["expires" => $expires]);
上述代碼會更新中間表的expires字段。
create方法使用create方法與save方法的不同在于它是使用數組的形式創建關聯模型的
$post = AppPost::find(1); $comment = $post->comments()->create([ "message" => "A new comment.", ]);更新 "Belongs To" 關系
更新belongsTo關系的時候,可以使用associate方法,該方法會設置子模型的外鍵
$account = AppAccount::find(10); $user->account()->associate($account); $user->save();
要移除belongsTo關系的話,使用dissociate方法
$user->account()->dissociate(); $user->save();Many to Many 關系 中間表查詢條件
當查詢時需要對使用中間表作為查詢條件時,可以使用wherePivot, wherePivotIn,orWherePivot,orWherePivotIn添加查詢條件。
$enterprise->with(["favorites" => function($query) { $query->wherePivot("enterprise_id", "=", 12)->select("id"); }]);Attaching / Detaching
$user = AppUser::find(1); // 為用戶添加角色 $user->roles()->attach($roleId); // 為用戶添加角色,更新中間表的expires字段 $user->roles()->attach($roleId, ["expires" => $expires]); // 移除用戶的單個角色 $user->roles()->detach($roleId); // 移除用戶的所有角色 $user->roles()->detach();
attach和detach方法支持數組參數,同時添加和移除多個
$user = AppUser::find(1); $user->roles()->detach([1, 2, 3]); $user->roles()->attach([1 => ["expires" => $expires], 2, 3]);更新中間表(關聯表)字段
使用updateExistingPivot方法更新中間表
$user = AppUser::find(1); $user->roles()->updateExistingPivot($roleId, $attributes);同步中間表(同步關聯關系)
使用sync方法,可以指定兩個模型之間只存在指定的關聯關系
$user->roles()->sync([1, 2, 3]); $user->roles()->sync([1 => ["expires" => true], 2, 3]);
上述兩個方法都會讓用戶只存在1,2,3三個角色,如果用戶之前存在其他角色,則會被刪除。
更新父模型的時間戳假設場景如下,我們為一個帖子增加了一個新的評論,我們希望這個時候帖子的更新時間會相應的改變,這種行為在Eloquent中是非常容易實現的。
在子模型中使用$touches屬性實現該功能
belongsTo("AppPost"); } }
現在,更新評論的時候,帖子的updated_at字段也會被更新
$comment = AppComment::find(1); $comment->text = "Edit to this comment!"; $comment->save();
參考: Eloquent: Relationships
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/21723.html
摘要:使用時,數據庫查詢構造器的方法對模型類也是也用的,使用上只是省略了表名部分。在模型中使用成員變量指定綁定的表名。 使用Eloquent [el?kw?nt] 時,數據庫查詢構造器的方法對模型類也是也用的,使用上只是省略了DB::table(表名)部分。 在模型中使用protected成員變量$table指定綁定的表名。
摘要:使用全局作用域功能可以為模型的所有操作增加約束。提供了一些方法可以方便的來實現數據類型之間的轉換。要定義一個,需要在模型中創建一個名稱為的方法,其中的是駝峰命名法的字段名。 查詢作用域 全局作用域 全局作用域允許你對給定模型的所有查詢添加約束。使用全局作用域功能可以為模型的所有操作增加約束。 軟刪除功能實際上就是利用了全局作用域功能 實現一個全局作用域功能只需要定義一個實現Illumi...
摘要:在中執行數據庫操作有兩種方式,一種是使用外觀對象的靜態方法直接執行查詢,另外一種是使用類的靜態方法實際上也是的實現,使用靜態訪問方式訪問的方法,內部采用了魔術方法代理了對成員方法的訪問。在閉包函數中,如果返回,則會停止后續的處理。 在Laravel中執行數據庫操作有兩種方式,一種是使用DB外觀對象的靜態方法直接執行sql查詢,另外一種是使用Model類的靜態方法(實際上也是Facade...
摘要:的現狀目前是版本,是基于開發。入口文件啟動文件和配置文件框架的入口文件是。在路由中指定控制器類必須寫全命名空間,不然會提示找不到類。目前支持四種數據庫系統以及。使用時發生錯誤,因為在文件中,的默認驅動是。 最近使用 Lumen 做了 2 個業余項目,特此記錄和分享一下。 Lumen 的介紹 在使用一項新的技術時,了解其應用場景是首要的事情。 Lumen 的口號:為速度而生的 La...
摘要:什么是官網是一個由組件搭建而成的微框架是當前最快的框架之一在什么時候使用專為微服務或者設計舉個例子如果你的應用里面有部分業務邏輯的請求頻率比較高就可以單獨把這部分業務邏輯拿出來使用來構建一個小因為是對優化了框架的加載機制所以對資源的要求少很 什么是 Lumen?官網 lumen 是一個由 Laravel 組件搭建而成的微框架,是當前最快的 PHP 框架之一! 在什么時候使用 Lume...
閱讀 3554·2021-11-25 09:43
閱讀 3135·2021-10-08 10:04
閱讀 1625·2019-08-26 12:20
閱讀 2053·2019-08-26 12:09
閱讀 595·2019-08-23 18:25
閱讀 3573·2019-08-23 17:54
閱讀 2322·2019-08-23 17:50
閱讀 803·2019-08-23 14:33