Laravel Eloquent ORM整理

來源:互聯網
上載者:User

介紹

Laravel 的 Eloquent ORM 提供了漂亮、簡潔的 ActiveRecord 實現來和資料庫的互動。 每個資料庫表會和一個對應的「模型」互動。

在開始之前,記得把 config/database.php 裡的資料庫連接配置好。

基本用法

我們先從建立一個 Eloquent 模型開始。模型通常放在 app 目錄下,但是您可以將它們放在任何地方,只要能通過 composer.json 自動載入。所有的 Eloquent 模型都繼承於 Illuminate\Database\Eloquent\Model .

  • 例如我放在app/Models下,則在composer.json中的配置如下:
  • "autoload-dev": {    "classmap": ["tests/TestCase.php", "app/Models"]},

    1. 建立[模型]

    手動建立

    在app/Models下建立檔案Logo.php

       

    命令建立

    php artisan make:model User
  • 命令建立的好處是:同時會在database/migrations 下產生對應的資料庫遷移檔案。
    注意我們並沒有告訴 Eloquent User 模型會使用哪個資料庫表。若沒有特別指定,系統會預設自動對應名稱為「類名稱的小寫複數形態」的資料庫表。所以,在上面的例子中, Eloquent 會假設 User 模型將把資料存在 users 資料庫表。您也可以在類中定義 table 屬性自訂要對應的資料庫表。
  • class Logo extends Model {    protected $table = 'my_logo';}
  • 注意: Eloquent 也會假設每個資料庫表都有一個欄位名稱為 id 的主鍵。您可以在類裡定義 primaryKey 屬性來重寫。同樣的,您也可以定義 connection 屬性,指定模型串連到指定的資料庫連接。
    定義好模型之後,您就可以從資料庫表新增及擷取資料了。注意在預設情況下,在資料庫表裡需要有 updated_at 和 created_at 兩個欄位。如果您不想設定或自動更新這兩個欄位,則將類裡的 $timestamps 屬性設為 false即可。
  • public $timestamps = false;

    2. 使用[模型]

    使用模型的方法

    取出所有記錄:$logos = Logo::all();

    根據主鍵取出一條資料:$logos = Logo::find(1);

    拆分查詢:傳到方法裡的第一個參數表示每次「拆分」要取出的資料數量。第二個參數的閉合函數會在每次取出資料時被調用。

    User::chunk(200, function($users) {   // 每次查詢200條    foreach ($users as $user)    {        //    }});
    其他方法就不一一列舉了,可以訪問:[eloquent ORM](http://laravel-china.org/docs/5.0/eloquent)
  • 如果沒辦法使用流暢介面產生出查詢語句,也可以使用 whereRaw 方法:
  • $users = User::whereRaw('age > ? and votes = 100', [25])->get();

    虛刪除

    通過虛刪除方式刪除了一個模型後,模型中的資料並不是真的從資料庫被移除。而是會設定 deleted_at時間戳記。要讓模型使用虛刪除功能,只要在模型類裡加入 SoftDeletingTrait 即可:

    use Illuminate\Database\Eloquent\SoftDeletes;class User extends Model {    use SoftDeletes;    protected $dates = ['deleted_at'];}

    要加入 deleted_at 欄位到資料庫表,可以在遷移檔案裡使用 softDeletes 方法:

    $table->softDeletes();

    現在當您使用模型調用 delete 方法時, deleted_at欄位會被更新成現在的時間戳記。在查詢使用虛刪除功能的模型時,被「刪除」的模型資料不會出現在查詢結果裡。

  • 普通查詢方法只能查詢到deleted_at為NULL的資料,也就是未被刪除/有效資料。要強制讓已被虛刪除的模型資料出現在查詢結果裡,在查詢時使用 withTrashed 方法:
  • $users = User::withTrashed()->where('account_id', 1)->get();
  • 如果您只想查詢被虛刪除的模型資料,可以使用 onlyTrashed 方法:
  • $users = User::onlyTrashed()->where('account_id', 1)->get();
  • 要把被虛刪除的模型資料恢複,使用 restore 方法:
  • $user->restore();
  • 您也可以結合查詢語句使用 restore :
  • User::withTrashed()->where('account_id', 1)->restore();
  • 如果想要真的從模型資料庫刪除,使用 forceDelete 方法:
  • $user->forceDelete();
  • 要確認模型是否被虛刪除了,可以使用 trashed 方法:
  • if ($user->trashed()){    //}

    範圍查詢

    定義範圍查詢

    範圍查詢可以讓您輕鬆的重複利用模型的查詢邏輯。要定義範圍查詢,只要定義有 scope 首碼的模型方法:

    class User extends Model {    public function scopePopular($query) {        return $query->where('votes', '>', 100);    }    public function scopeWomen($query) {        return $query->whereGender('W');    }}
    使用範圍查詢
    $users = User::popular()->women()->orderBy('created_at')->get();
    動態範圍查詢

    有時您可能想要定義可接受參數的範圍查詢方法。只要把參數加到方法裡:

    class User extends Model {    public function scopeOfType($query, $type) {        return $query->whereType($type);    }}

    然後把參數值傳到範圍查詢方法調用裡:

    $users = User::ofType('member')->get();

    3. 關聯

    一對一

    定義一對一關聯

    一對一關聯是很基本的關聯。例如一個 User 模型會對應到一個 Phone 。 在 Eloquent 裡可以像下面這樣定義關聯:

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

    傳到 hasOne 方法裡的第一個參數是關聯模型的類名稱。定義好關聯之後,就可以使用 Eloquent 的動態屬性取得關聯對象:

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

    SQL 會執行如下語句:

    select * from users where id = 1select * from phones where user_id = 1
  • 注意, Eloquent 假設對應的關聯模型資料庫表裡,外鍵名稱是基於模型名稱。在這個例子裡,預設 Phone 模型資料庫表會以 user_id 作為外鍵。如果想要更改這個預設,可以傳入第二個參數到 hasOne 方法裡。更進一步,您可以傳入第三個參數,指定關聯的外鍵要對應到本身的哪個欄位:
  • return $this->hasOne('App\Phone', 'foreign_key');return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
    定義相對的關聯

    要在 Phone 模型裡定義相對的關聯,可以使用 belongsTo 方法:

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

    在上面的例子裡, Eloquent 預設會使用 phones 資料庫表的 user_id 欄位查詢關聯。如果想要自己指定外鍵欄位,可以在 belongsTo 方法裡傳入第二個參數:

    class Phone extends Model {    public function user() {        return $this->belongsTo('App\User', 'local_key');    }}

    除此之外,也可以傳入第三個參數指定要參照上層資料庫表的哪個欄位:

    class Phone extends Model {    public function user() {        return $this->belongsTo('App\User', 'local_key', 'parent_key');    }}

    一對多

    定義一對多關聯

    一對多關聯的例子如,一篇 Blog 文章可能「有很多」評論。可以像這樣定義關聯:

    class Post extends Model {    public function comments() {        return $this->hasMany('App\Comment');    }}

    現在可以經由動態屬性取得文章的評論:

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

    如果需要增加更多條件限制,可以在調用 comments 方法後面通過鏈式查詢條件方法:

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

    同樣的,您可以傳入第二個參數到 hasMany 方法更改預設的外鍵名稱。以及,如同 hasOne 關聯,可以指定本身的對應欄位:

    return $this->hasMany('App\Comment', 'foreign_key');return $this->hasMany('App\Comment', 'foreign_key', 'local_key');
    定義相對的關聯

    要在 Comment 模型定義相對應的關聯,可使用 belongsTo 方法:

    class Comment extends Model {    public function post() {        return $this->belongsTo('App\Post');    }}

    多對多

    定義多對多關聯

    多對多關聯更為複雜。這種關聯的例子如,一個使用者( user )可能用有很多身份( role ),而一種身份可能很多使用者都有。例如很多使用者都是「管理者」。多對多關聯需要用到三個資料庫表: users , roles ,和 role_user 。 role_user 樞紐表命名是以相關聯的兩個模型資料庫表,依照字母順序命名,樞紐表裡面應該要有 user_id 和 role_id 欄位。

    可以使用 belongsToMany 方法定義多對多關係:

    class User extends Model {    public function roles() {        return $this->belongsToMany('App\Role');    }}class Role extends Model {    public function users() {        return $this->belongsToMany('App\User');    }}

    現在我們可以從 User 模型取得 roles:

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

    如果不想使用預設的樞紐資料庫表命名方式,可以傳遞資料庫表名稱作為 belongsToMany 方法的第二個參數:

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

    也可以更改預設的關聯欄位名稱:

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

    Has Many Through 遠層一對多關聯

    「遠層一對多關聯」提供了方便簡短的方法,可以經由多層間的關聯取得遠層的關聯。例如,一個 Country 模型可能通過 Users 關聯到很多 Posts 模型。 資料庫表間的關係可能看起來如下:

    countries    id - integer    name - stringusers    id - integer    country_id - integer    name - stringposts    id - integer    user_id - integer    title - string

    雖然 posts 資料庫表本身沒有 country_id 欄位,但 hasManyThrough 方法讓我們可以使用 $country->posts 取得 country 的 posts。我們可以定義以下關聯:

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

    如果想要手動指定關聯的欄位名稱,可以傳入第三和第四個參數到方法裡:

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

    關聯查詢

    根據關聯條件查詢

    在取得模型資料時,您可能想要以關聯模型作為查詢限制。例如,您可能想要取得所有「至少有一篇評論」的Blog 文章。可以使用 has 方法達成目的:

    $posts = Post::has('comments')->get();

    也可以指定運算子和數量:

    $posts = Post::has('comments', '>=', 3)->get();

    也可以使用”點號”的形式來擷取嵌套的 has 聲明:

    $posts = Post::has('comments.votes')->get();

    如果想要更進階的用法,可以使用 whereHas 和 orWhereHas 方法,在 has 查詢裡設定 “where” 條件 :

    $posts = Post::whereHas('comments', function($q){    $q->where('content', 'like', 'foo%');})->get();

    動態屬性

    Eloquent 可以經由動態屬性取得關聯對象。 Eloquent 會自動進行關聯查詢,而且會很聰明的知道應該要使用 get(用在一對多關聯)或是 first (用在一對一關聯)方法。可以經由和「關聯方法名稱相同」的動態屬性取得對象。例如,如下面的模型對象 $phone:

    class Phone extends Model {    public function user() {        return $this->belongsTo('App\User');    }}$phone = Phone::find(1);

    您可以不用像下面這樣列印使用者的 email :echo $phone->user()->first()->email;
    而可以簡寫如下:echo $phone->user->email;

  • 若取得的是許多關聯對象,會返回 Illuminate\Database\Eloquent\Collection 對象。
  • 預載入

    預載入是用來減少 N + 1 查詢問題。例如,一個 Book 模型資料會關聯到一個 Author 。關聯會像下面這樣定義:

    class Book extends Model {    public function author() {        return $this->belongsTo('App\Author');    }}

    現在考慮下面的代碼:

    foreach (Book::all() as $book){    echo $book->author->name;}

    上面的迴圈會執行一次查詢取回所有資料庫表上的書籍,然而每本書籍都會執行一次查詢取得作者。所以若我們有 25 本書,就會進行 26次查詢。

    很幸運地,我們可以使用預載入大量減少查詢次數。使用 with 方法指定想要預載入的關聯對象:

    foreach (Book::with('author')->get() as $book) { echo $book->author->name;}

    現在,上面的迴圈總共只會執行兩次查詢:

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

    使用預載入可以大大提高程式的效能。

    當然,也可以同時載入多種關聯:

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

    預載入條件限制

    有時您可能想要預載入關聯,同時也想要指定載入時的查詢限制。下面有一個例子:

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

    上面的例子裡,我們預載入了 user 的 posts 關聯,並限制條件為 post 的 title 欄位需包含 “first” 。

    當然,預載入的閉合函數裡不一定只能加上條件限制,也可以加上排序:

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

    新增關聯模型

    附加一個關聯模型

    您常常會需要加入新的關聯模型。例如新增一個 comment 到 post 。除了手動設定模型的 post_id 外鍵,
    也可以從上層的 Post 模型新增關聯的 comment :

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

    上面的例子裡,新增的 comment 模型中 post_id 欄位會被自動設定。

    如果想要同時新增很多關聯模型:

    $comments = [    new Comment(['message' => 'A new comment.']),    new Comment(['message' => 'Another comment.']),    new Comment(['message' => 'The latest comment.'])];$post = Post::find(1);$post->comments()->saveMany($comments);

    從屬關聯模型 ( Belongs To )

    要更新 belongsTo 關聯時,可以使用 associate 方法。這個方法會設定子模型的外鍵:

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

    新增多對多關聯模型 ( Many To Many )

    您也可以新增多對多的關聯模型。讓我們繼續使用 User 和 Role 模型作為例子。我們可以使用 attach 方法簡單地把 roles 附加給一個 user:

    附加多對多模型

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

    也可以傳入要存在樞紐表中的屬性數組:

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

    當然,有 attach 方法就會有相反的 detach 方法:

    $user->roles()->detach(1);

    attach 和 detach 都可以接受ID數組作為參數:

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

    使用 Sync 方法同時附加一個以上多對多關聯

    您也可以使用 sync 方法附加關聯模型。 sync 方法會把根據 ID 數組把關聯存到樞紐表。附加完關聯後,樞紐表裡的模型只會關聯到 ID 數組裡的 id :

    $user->roles()->sync([1, 2, 3]);
    Sync 時在樞紐表加入額外資料

    也可以在把每個 ID 加入樞紐表時,加入其他欄位的資料:

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

    有時您可能想要使用一個命令,在建立新模型資料的同時附加關聯。可以使用 save 方法達成目的:

    $role = new Role(['name' => 'Editor']);User::find(1)->roles()->save($role);

    上面的例子裡,新的 Role 模型對象會在儲存的同時關聯到 user 模型。也可以傳入屬性數組把資料加到關聯資料庫表:

    User::find(1)->roles()->save($role, ['expires' => $expires]);
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.