欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

Laravel Eloquent—模型间关系(关联)

shiping1 的头像
Eloquent是什么


Eloquent 是一个 ORM,全称为 Object Relational Mapping,翻译为 “对象关系映射”(如果只把它当成 Database Abstraction Layer 数组库抽象层那就太小看它了)。所谓 “对象”,就是本文所说的 “模型(Model)”;对象关系映射,即为模型间关系。中文文档: http://laravel-china.org/docs/eloquent#relationships

下面我们开始一个一个地学习。
一对一关系

顾名思义,这描述的是两个模型之间一对一的关系。这种关系是不需要中间表的。

假如我们有两个模型:User 和 Account,分别对应注册用户和消费者,他们是一对一的关系,那么如果我们要使用 Eloquent 提供的一对一关系方法,表结构应该是这样的:

user: id ... ... account_id

account: id ... ... user_id

假设我们需要在 User 模型中查询对应的 Account 表的信息,那么代码应该是这样的。 `/app/models/User.php`:
 

1
2
3
4
5
6
7
8
9
<?php
class User extends Eloquent {
  
  protected $table 'users';
  public function hasOneAccount()
  {
      return $this->hasOne('Account''user_id''id');
  }
}

然后,当我们需要用到这种关系的时候,该如何使用呢?如下:

$account = User::find(10)->hasOneAccount;

此时得到的 `$account` 即为 `Account` 类的一个实例。

这里最难的地方在于后面的两个 foreign_key 和 local_key 的设置,大家可以就此记住:在 User 类中,无论 hasOne 谁,第二个参数都是 `user_id`,第三个参数一般都是 `id`。由于前面的 `find(10)` 已经锁定了 id = 10,所以这段函数对应的 SQL 为: `select * from account where user_id=10`。

这段代码除了展示了一对一关系该如何使用之外,还传达了三点信息,也是我对于大家使用 Eloquent 时候的建议:

    1. 每一个 Model 中都指定表名

    2. has one account 这样的关系写成 `hasOneAccount()` 而不是简单的 `account()`

    3. 每次使用模型间关系的时候都写全参数,不要省略

相应的,如果使用 belongsTo() 关系,应该这么写:
 

1
2
3
4
5
6
7
8
9
<?php
class Account extends Eloquent {
  protected $table 'accounts';
  
  public function belongsToUser()
  {
    return $this->belongsTo('User''user_id''id');
  }
}

一对多关系

学会了前面使用一对一关系的基础方法,后面的几种关系就简单多了。

我们引入一个新的Model:Pay,付款记录。表结构应该是这样的:

user: id ... ...

pay: id ... ... user_id

User 和 Pay 具有一对多关系,换句话说就是一个 User 可以有多个 Pay,这样的话,只在 Pay 表中存在一个 `user_id` 字段即可。 `/app/models/User.php`:
 

1
2
3
4
5
6
7
8
9
<?php
class User extends Eloquent {
  
  protected $table 'users';
  public function hasManyPays()
  {
    return $this->hasMany('Pay''user_id''id');
  }
}

然后,当我们需要用到这种关系的时候,该如何使用呢?如下:

$accounts = User::find(10)->hasManyPays()->get();

此时得到的 `$accounts` 即为 `Illuminate\Database\Eloquent\Collection` 类的一个实例。大家应该也已经注意到了,这里不是简单的 `-> hasOneAccount` 而是 `->hasManyPays()->get()`,为什么呢?因为这里是 `hasMany`,操作的是一个对象集合。

相应的 belongsTo() 的用法跟上面一对一关系一样:
 

1
2
3
4
5
6
7
8
9
<?php
class Pay extends Eloquent {
  protected $table 'pays';
  
  public function belongsToUser()
  {
    return $this->belongsTo('User''user_id''id');
  }
}

多对多关系

多对多关系和之前的关系完全不一样,因为多对多关系可能出现很多冗余数据,用之前自带的表存不下了。

我们定义两个模型:Article 和 Tag,分别表示文章和标签,他们是多对多的关系。表结构应该是这样的:

article: id ... ...

tag: id ... ...

article_tag: article_id tag_id

在 Model 中使用:
 

1
2
3
4
5
6
7
8
9
<?php
class Tag extends Eloquent {
  protected $table 'tags';
  
  public function belongsToManyArticle()
  {
    return $this->belongsToMany('Article''article_tag''tag_id''article_id');
  }
}

需要注意的是,第三个参数是本类的 id,第四个参数是第一个参数那个类的 id。

使用跟 hasMany 一样:

$tagsWithArticles = Tag::take(10)->get()->belongsToManyArticle()->get();

这里会得到一个非常复杂的对象,可以自行 `var_dump()`。跟大家说一个诀窍,`var_dump()` 以后,用 Chrome 右键 “查看源代码”,就可以看到非常整齐的对象/数组展开了。

    在这里给大家展示一个少见用法(奇技淫巧):

   

1
2
3
4
5
6
7
8
public function parent_video()
    {
        return $this->belongsToMany($this'video_hierarchy''video_id''video_parent_id');
    }
    public function children_video()
    {
        return $this->belongsToMany($this'video_hierarchy''video_parent_id''video_id');
    }

    对,你没有看错,可以 belongsToMany 自己。

普通分类: