https://laravelacademy.org/post/9699.html
建議用DB門面直接操作數據庫,因為ORM性能低。數據查詢上面,ORM不會比DB差的,就比如with,是用了sql最基本的拆語句優化。ORM的損耗僅僅是代碼層面的,這已經不算是問題了。
ORM適用於一般到中等復雜度的查詢,也適用於各種模型操作,比如有一個關系targets,你可以直接用targets()->delete()等等進行關系數據操作。
ORM中的軟刪除,自動更新時間字段,字段保護,字段類型轉換,都會在一些規范而且系統的工程中讓你受益。
另外DB的場景:一些比較復雜的查詢語句,事務操作,等都需要DB來完成。
模型類定義 使用模型類之前,需要在數據庫有對應的數據表,因為模型類就是數據表在面向對象編程語言中的映射。比如我們前面幾篇教程中用到的 User 模型和 Post 模型都是這樣,要創建一個模型類,需要使用 make:model 命令: php artisan make:model Post 注:如果對應的數據表尚未創建,你還可以在創建模型類的同時創建對應的數據庫遷移文件,通過 php artisan make:model Post -m 即可。如果你想將模型類創建到 app/Models 目錄下,可以這么運行上述命令 php artisan make:model Models/Post。 接下來我們就是 posts 表映射的 Post 模型為例,來看看默認都有哪些約定。新生成的 Post 模型類如下: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { // } 里面什么東西都沒有,但是我們就可以通過它完成數據表記錄的增刪改查操作了,怎么做到的?這就是「約定優於配置」的功勞了。下面我們就來看看這些默認的約定。 表名 Eloquent 約定模型類映射表名是將類名由駝峰格式轉化為小寫+下划線(含多個單詞的話),最后將其轉化為復數形式,比如 Post 對應表名是 posts、PostTag 對應表名是 post_tags 等等。當然,如果你不想遵循這個系統約定的規則,也可以通過手動設置模型類屬性的方式進行自定義,例如: protected $table = 'articles'; 主鍵 Eloquent 默認假設每張數據表都有一個整型的自增主鍵,其字段名為 id,如果你的數據表主鍵名不是 id,可以通過 $primaryKey 屬性來指定: protected $primaryKey = 'post_id'; 如果主鍵不是自增的,還可以設置 $incrementing 屬性為 false: public $incrementing = false; 如果主鍵不是整型,還可以設置 $keyType 屬性為 string: protected $keyType = 'string'; 時間戳 Eloquent 默認約定每張表都有 created_at 和 updated_at 字段(遷移類中 $table->timestamps() 會生成這兩個字段),並且在保存模型類時會自動維護這兩個字段。如果你的數據表里面不包含這兩個字段,或者只包含一個,都需要設置 $timestamps 屬性為 false: public $timestamps = false; 或者通過 CREATED_AT 和 UPDATED_AT 常量來設置自定義的創建和更新時間字段: public const CREATED_AT = 'create_time'; public const UPDATED_AT = 'update_time'; 此外,默認時間的存儲格式是 Y-m-d H:i:s,你還可以通過 $dateFormat 屬性來自定義時間戳的格式,該屬性值通過 PHP 的 date() 函數進行解析,所以原則上支持 date 函數支持的所有語法格式,比如將時間設置為 Unix 時間戳: protected $dateFormat = 'U'; 這樣,保存到數據庫的時間格式就是 Unix 時間戳了,前提是你的 created_at 和 updated_at 字段是整型,否則會報格式錯誤。 數據庫連接 Eloquent 模型類默認約定的數據庫連接是 config/database.php 中配置的默認連接,正如我們在連接配置教程中所說的那樣,如果應用配置了多個數據庫連接,可以通過 $connection 屬性為模型類指定使用哪個連接: protected $connection = 'connection_name'; 查詢數據 日常開發中,大部分操作都是數據庫中查詢數據,Eloquent 模型了為我們提供了很多方法幫助我們從數據庫中獲取數據。 獲取所有記錄 我們可以通過模型類提供的 all 方法獲取一張表的所有記錄: $posts = Post:all(); 和查詢構建器一樣,該方法返回的也是集合,只不過是模型類集合: 要獲取指定模型類的字段屬性,遍歷該集合即可: foreach ($posts as $post) { dump($post->title); } 和查詢構建器一樣,如果結果集很大的話,模型類也支持通過 chunk 方法分塊獲取查詢結果: Post::chunk(10, function ($posts) { foreach ($posts as $post) { if ($post->views == 0) { continue; } else { dump($post->title . ':' . $post->views); } } }); 除此之外,在 Eloquent 模型中還可以通過 cursor 方法每次只獲取一條查詢結果,從而最大限度減少內存消耗: foreach (Post::cursor() as $post) { dump($post->title . ':' . $post->content); } 獲取指定查詢結果 如果想要指定查詢條件和查詢字段,可以通過 where 方法和 select 方法來實現: $posts = Post::where('views', '>', 0)->select('id', 'title', 'content')->get(); 對應查詢結果如下: 實際上,Eloquent 模型類底層的查詢也是基於查詢構建器來實現的,你可以在模型類上調用所有查詢構建器的 Where 查詢方法,同樣是以流接口的模式構建方法鏈調用即可。前面提到的 chunk 和 cursor 方法也適用於這種指定查詢條件的查詢操作。 因為是查詢構建器,所以我們還可以在模型查詢操作中對查詢結果進行排序和分頁: $posts = Post::where('views', '>', 0)->orderBy('id', 'desc')->offset(10)->limit(5)->get(); 對應的返回結果如下: 獲取單條記錄 當然,你也可以通過查詢構建器的方式在模型類查詢中獲取單條記錄: $user = User::where('name', '學院君')->first(); 返回的結果是一個模型類實例: 你可以直接通過 $user->name 這樣的方式訪問模型類實例的屬性。 此外,如果查詢的條件是主鍵 ID 的話,還可以將上述調用簡化為通過 find 方法來實現: $user = User::find(1); 返回結果與上面完全一致。 模型類查詢結果為空會返回 null。如果你想要在單條記錄返回結果為空時返回 404 響應(在控制器方法中可能需要用到類似操作),可以通過 firstOrFail 或者 findOrFail 方法在找不到對應記錄時拋出 404 異常,從而簡化代碼編寫: $user = User::findOrFail(111); 如果 id=111 的記錄在 users 數據表中不存在,就會返回 404 響應: 獲取聚合結果 Eloquent 模型類同樣支持 count、sum、avg、max、min 等聚合函數查詢: $num = User::whereNotNull('email_verified_at')->count(); # 計數 $sum = User::whereNotNull('email_verified_at')->sum('id'); # 求和 $avg = User::whereNotNull('email_verified_at')->avg('id'); # 平均值 $min = User::whereNotNull('email_verified_at')->min('id'); # 最小值 $max = User::whereNotNull('email_verified_at')->max('id'); # 最大值 你會發現,如果你掌握了查詢構建器,就等同於掌握了 Laravel 中的所有數據庫查詢操作。只不過將 DB::table 換成對應的模型類而已。 注:除獲取單條記錄之外,ELoquent 模型類查詢返回的結果都是集合類,因此你可以在查詢結果上調用集合類的所有方法,還可以自定義模型對應集合類,詳情請查看對應官方文檔。 插入數據 通過 Eloquent 模型類插入記錄到數據庫也比較簡單: $post = new App\Post; $post->title = '測試文章標題'; $post->content = '測試文章內容'; $post->user_id = 1; $post->save(); 創建時間和更新時間字段由 Eloquent 底層自動幫我們維護(遵循默認約定的話)。執行上面的代碼就會在數據庫新增一條記錄(我們在 Tinker 中執行上述代碼): 我們先要創建一個新的 Post 模型實例,然后依次設置需要設置的字段,最后調用 save 方法保存即可。 此外,Eloquent 還為我們提供了一些快捷的插入方法,比如 firstOrCreate 和 firstOrNew,這兩個方法都會先嘗試通過指定查詢條件在數據庫中查找對應記錄,如果沒有找到的話,會創建對應模型類的實例,並將查詢條件作為對應字段值設置到模型屬性上。兩者的區別是 firstOrCreate 方法在設置完模型屬性后會將該模型記錄保存到數據庫中,而 firstOrNew 不會: $post_1 = Post::firstOrCreate([ 'title' => '測試文章標題1', 'user_id' => 1, ]); $post_2 = Post::firstOrNew([ 'title' => '測試文章標題1', 'user_id' => 1, ]); 不過學院君倒不建議這么做,感覺還是分開寫代碼可讀性更好一些,也方便自己去處理一些異常情況。 更新數據 通過模型類更新數據表記錄也很簡單: $post = Post::find(31); $post->title = '測試文章標題更新'; $post->save(); 更新時間 Eloquent 底層會自動幫我們維護,執行上面的代碼即可完成該 $post 模型對應數據表記錄的更新: 同樣,Eloquent 也為我們提供了快捷的更新方法 updateOrCreate,該方法首先會根據傳入參數對模型對應記錄進行更新,如果發現對應記錄不存在,則會將更新數據作為初始數據插入數據庫,並保存(同樣也不建議這么做,除非你的場景特別適合): $user = user::updateOrCreate( ['name' => '學院君'], ['email' => 'admin@laravelacademy.org'] ); 有的時候我們可能需要批量更新模型對應數據表的多條記錄,這可以借助查詢構建器來實現: Post::where('views', '>', 0)->update(['views' => 100]); 刪除數據 通過模型類刪除對應數據表記錄和更新記錄類似,都要先獲取對應操作模型實例,刪除對應記錄更簡單,獲取到模型實例后,直接調用其刪除方法即可: $post = Post::find(31); $post->delete(); 這樣,就完成了 id = 31 對應數據表記錄的刪除,你還可以通過 Eloquent 提供的 destroy 方法一次刪除多條記錄,通過數組傳遞多個主鍵 ID 即可: Post::destroy([1,2,3]); 當然,你也可以通過查詢構建器的方式刪除指定記錄: $user = User::where('name', '學院君')->fisrt(); $user->delete(); 結語 在這篇教程中,我們簡單給大家介紹了 Eloquent 是什么,以及「約定優於配置」理念在 Eloquent 中的應用,最后還給大家演示了如何通過 Eloquent 實現數據庫的增刪改查,當然,Eloquent 的功能遠不僅如此,還支持很多強大的功能,比如批量賦值、軟刪除、查詢作用域設置、模型事件、關聯關系等,下一篇教程開始學院君將帶領大家來逐一了解這些高階功能。