您的位置:首页 > 编程语言 > PHP开发

深入理解 Laravel Eloquent(三)——模型间关系(关联)

2015-01-10 00:30 549 查看

原文发表在我的个人网站:深入理解 Laravel Eloquent(三)——模型间关系(关联)

在本篇文章中,我将跟大家一起学习 Eloquent 中最复杂也是最难理解的部分——模型间关系。官方英文文档中叫 Relationships,个人认为翻译成 “模型间关系” 比现在的 “关联” 更好理解一点哈哈。

Eloquent是什么

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

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

一对一关系

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

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

ruby
user: id ... ... account_id
account: id ... ... user_id

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

/app/models/User.php
:

php
<?php

class User extends Eloquent {

protected $table = 'users';

public function hasOneAccount()
{
return $this->hasOne('Account', 'user_id', 'id');
}
}

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

php
$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() 关系,应该这么写:

php
<?php

class Account extends Eloquent {

protected $table = 'accounts';

public function belongsToUser()
{
return $this->belongsTo('User', 'user_id', 'id');
}
}

一对多关系

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

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

ruby
user: id ... ...
pay: id ... ... user_id

User 和 Pay 具有一对多关系,换句话说就是一个 User 可以有多个 Pay,这样的话,只在 Pay 表中存在一个

user_id
字段即可。
/app/models/User.php
:

php
<?php

class User extends Eloquent {

protected $table = 'users';

public function hasManyPays()
{
return $this->hasMany('Pay', 'user_id', 'id');
}
}

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

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

此时得到的

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

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

php
<?php

class Pay extends Eloquent {

protected $table = 'pays';

public function belongsToUser()
{
return $this->belongsTo('User', 'user_id', 'id');
}
}

多对多关系

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

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

ruby
article: id ... ...
tag: id ... ...
article_tag: article_id tag_id

在 Model 中使用:

php
<?php

class Tag extends Eloquent {

protected $table = 'tags';

public function belongsToManyArticle()
{
return $this->belongsToMany('Article', 'article_tag', 'tag_id', 'article_id');
}
}

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

使用跟 hasMany 一样:

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

这里会得到一个非常复杂的对象,可以自行

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

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

php
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 自己。

其他关系

Eloquent 还提供 “远层一对多关联”、“多态关联” 和 “多态的多对多关联” 这另外三种用法,经过上面的学习,我们已经掌握了 Eloquent 模型间关系的基本概念和使用方法,剩下的几种不常用的方法就留到我们用到的时候再自己探索吧。

重要技巧:关系预载入

你也许已经发现了,在一对一关系中,如果我们需要一次性查询出10个 User 并带上对应的 Account 的话,那么就需要给数据库打 1 + 10 条 SQL,这样性能是很差的。我们可以使用一个重要的特性,关系预载入:http://laravel-china.org/docs/eloquent#eager-loading

直接上代码:

php
$users = User::with('hasOneAccount')->take(10)->get()

这样生成的 SQL 就是这个样子的:

sql
select * from account where id in (1, 2, 3, ... ...)

这样 1 + 10 条 SQL 就变成了 1 + 1 条,性能大增。


至此,深入理解 Laravel Eloquent 系列文章到此结束。推荐继续了解 软删除 、转换成数组/JSON。

END

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: