您现在的位置是:网站首页 > 心得笔记

laravel框架中简单的模型关联

盛悦2019-07-17603人围观
简介laravel框架中简单的模型关联知识总结

1.1、一对一

模型说明:一个 User 模型关联一个 Phone 模型

两种关联方式:
1、正向关联 hasOne
在 User 模型中写一个 phone 方法,在 phone 方法内部调用 hasOne 方法并返回其结果:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
   /**
    * 获得与用户关联的电话记录。
    */
   public function phone()
   {
       return $this->hasOne('App\Phone','user_id','id');
      /*重要技巧!!!!
      第一个参数是关联模型的类名
      第二个参数 foreign_key 是使用的外键名   Eloquent 会基于模型名决定外键名称 User模型对应外键user_id
      第三个参数 local_key 是自定义键名
      */
   }
}



2、反向关联 belongsTo
 我们已经能从 User 模型访问到 Phone 模型了。现在,再在 Phone 模型中定义一个关联,此关联能让我们访问到拥有此电话的 User 模型。这时,使用的是与 hasOne 方法对应的 belongsTo 方法:
 
 <?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model
{
   /**
    * 获得拥有此电话的用户。
    */
   public function user()
   {
       return $this->belongsTo('App\User','user_id','id');
       /*重要技巧!!!!
         第一个参数是关联模型的类名
         第二个参数 foreign_key 是使用的外键名   通过检查关系方法的名称并使用 _id 作为后缀名来确定默认外键名称
         第三个参数 local_key 是自定义键名
         */
   }
}
 
 
 
 

1.2、一对多

模型说明:一个 Post 模型关联一个 Comment 模型

两种关联方式:
1、正向关联 hasMany
一篇博客文章可能会有无限多条评论。就像其它的 Eloquent 关联一样,一对多关联的定义也是在 Eloquent 模型中写一个方法:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
   /**
    * 获得此博客文章的评论。
    */
   public function comments()
   {
       return $this->hasMany('App\Comment','post_id','id');
       /*重要技巧!!!!
           第一个参数是关联模型的类名
           第二个参数 foreign_key 是使用的外键名  父级模型名加上 _id 后缀名作为外键字段
           第三个参数 local_key 是自定义键名
           */
   }
}

2、反向关联 belongsTo
 我们已经能获得一篇文章的所有评论,接着再定义一个通过评论获得所属文章的关联。这个关联是 hasMany 关联的反向关联,在子级模型中使用 belongsTo 方法定义它:
 
 <?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
   /**
    * 获得此评论所属的文章。
    */
   public function post()
   {
       return $this->belongsTo('App\Post','post_id','id');
     /*重要技巧!!!!
           第一个参数是关联模型的类名
           第二个参数 foreign_key 是使用的外键名  默认外键名是 Eloquent 依据关联方法名、并在关联名后加上 _id 后缀确定的
           第三个参数 local_key 是自定义键名   父级模型的主键
           */
   }
}

关联模型计数

如果想要只计算关联结果的统计数量而不需要真实加载它们,可以使用 withCount 方法,它将放在结果模型的 {relation}_count 列。示例如下:

$posts = App\Post::withCount('comments')->get();foreach ($posts as $post) {
    echo $post->comments_count;}

可以像给查询添加限制一样为多个关系添加「计数」:

$posts = App\Post::withCount(['votes', 'comments' => function ($query) {
    $query->where('content', 'like', 'foo%');}])->get();echo $posts[0]->votes_count;echo $posts[0]->comments_count;

还可以给关联计数结果起别名,这允许你在同一关联上添加多个计数:

$posts = App\Post::withCount([
    'comments',
    'comments as pending_comments_count' => function ($query) {
        $query->where('approved', false);
    }])->get();echo $posts[0]->comments_count;echo $posts[0]->pending_comments_count;

如果将 withCountselect 查询组装在一起,请确保在 select 方法之后调用 withCount

$query = App\Post::select(['title', 'body'])->withCount('comments');echo $posts[0]->title;echo $posts[0]->body;echo $posts[0]->comments_count;


预加载

当以属性方式访问 Eloquent 关联时,关联数据「懒加载」。这着直到第一次访问属性时关联数据才会被真实加载。不过 Eloquent 能在查询父模型时「预先载入」子关联。预加载可以缓解 N + 1 查询问题。为了说明 N + 1 查询问题,考虑  Book 模型关联到 Author 的情形:

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Book extends Model{
    /**
     * 获取书籍作者。
     */
    public function author()
    {
        return $this->belongsTo('App\Author');
    }}

现在,我们来获取所有的书籍及其作者:

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

此循环将执行一个查询,用于获取全部书籍,然后为每本书执行获取作者的查询。如果我们有 25 本书,此循环将运行 26 个查询:1 个用于查询书籍,25 个附加查询用于查询每本书的作者。

谢天谢地,我们能够使用预加载将操作压缩到只有 2 个查询。在查询时,可以使用 with 方法指定想要预加载的关联:

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

在这个例子中,仅执行了两个查询:

select * from books

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

预加载多个关联

有时,你可能需要在单一操作中预加载几个不同的关联。要达成此目的,只要向 with 方法传递多个关联名称构成的数组参数:

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

嵌套预加载

可以使用 「点」 语法预加载嵌套关联。比如在一个 Eloquent 语句中预加载所有书籍作者及其联系方式:

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

预加载指定列

并不是总需要获取关系的每一列。在这种情况下,Eloquent 允许你为关联指定想要获取的列:

$users = App\Book::with('author:id,name')->get();

{note} 在使用这个特性时,一定要在要获取的列的列表中包含 id 列。

为预加载添加约束

有时,可能希望预加载一个关联,同时为预加载查询添加额外查询条件,就像下面的例子:

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

在这个例子中, Eloquent 将仅预加载那些 title 列包含 first 关键词的文章。也可以调用其它的 查询构造器 方法进一步自定义预加载操作:

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

{note} 在约束预加载时,不能使用 limittake 查询构造器方法。