3分钟短文:Laravel模型一对一一对多关系真的乱吗?

2020-09-21 15:27:37 浏览数 (1)

引言

laravel模型不但提供了可供数据库操作的增删改查,还附加了很多功能,最关键的要数模型的关联关系。本文说一说简单的一对一,和一对多关系。用代码说话,让大家更直观地理解。

代码时间

例如一个通讯录条目,一条通讯录,有一个手机号码,这是个一对一的关系。在Contact模型文件内创建关联方法:

代码语言:javascript复制
class Contact extends Model{    public function phoneNumber()
    {
        return $this->hasOne(PhoneNumber::class);
    }}

上面这个写法,默认是有一个模型 PhoneNumber 所对应的表,且表内有一个字段名 contacts_id 作为外键。如果这个外键不是 contacts_id,那就手动指定:

代码语言:javascript复制
return $this->hasOne(PhoneNumber::class, 'owner_id');

使用 phone_numbers 表的 owner_id 进行关联。使用的时候,先获取Contact条目,然后使用关联方法获取PhoneNumber对象, 代码是这样的:

代码语言:javascript复制
$contact = Contact::first();$contactPhone = $contact->phoneNumber;

变量 $contactPhone 就是一个模型对象,可以直接访问其各个属性。有同学会疑问, 这中间是靠什么办法关联获取的呢?都是数据库的条目,一定是走SQL查询了吧?

没错,laravel也的确是这样做的。先查找contacts条目:

代码语言:javascript复制
select * from contacts where 1 limit 1; 

然后获取的 owner_id 比如等于47,那么接着查找 phone_numbers 表:

代码语言:javascript复制
select * from phone_numbers where owner_id = 47; 

每一条SQL都充分利用索引,可以准确快速地拿到结果。

有了一对一关系,我们能不能从手机号码倒推,反向查询到通讯录条目呢?当然是可以的,这就是 一对一的逆函数 belongsTo

代码语言:javascript复制
class PhoneNumber extends Model{    public function contact()
    {
        return $this->belongsTo(Contact::class);
    }}

与上方的调用关系相同,我们先查找到手机号,然后使用关联函数返回Contact模型:

代码语言:javascript复制
$contact = $phoneNumber->contact;

laravel还有一个高级用法,关联插入新的条目。比如写入一条contact,同时更新phone_number。我们只需在关联关系基础上,链式调用save方法,传入一个关联模型实例。如果要写入多条的,就传入一个 关联模型实例的数组。

用代码演示一下:

代码语言:javascript复制
$contact = Contact::first();$phoneNumber = new PhoneNumber;$phoneNumber->number = 123123123;$contact->phoneNumbers()->save($phoneNumber);

上面是查询出某条contact,然后更新关联模型的手机号。这是写入一条,你也可以写入多条:

代码语言:javascript复制
$contact->phoneNumbers()->saveMany([PhoneNumber::find(1),PhoneNumber::find(2)]);

或者知道关联模型字段名的,调用模型的create方法,传入一个数组,用于新建:

代码语言:javascript复制
$contact->phoneNumbers()->create(['number' => '123123123']);

有了一对一的铺垫,我们理解一对多就简单的多了。例如一个用户有多条通讯录,模型内定义如下:

代码语言:javascript复制
class User extends Model{    public function contacts()
    {
        return $this->hasMany(Contact::class);
    }}

那么使用链式调用关联关系方法是,返回的就是一个 Eloquent Collection,例如:

代码语言:javascript复制
$user = User::first();$usersContacts = $user->contacts;

是集合就可以充分利用集合的函数方法操作数据集。比如返回所有有效的通讯录:

代码语言:javascript复制
$actives = $user->contacts->filter(function ($contact) {
    return $contact->status == 'active';});

比如对于Contact模型,加入关联了Order订单模型,且是一对多,将符合条件的订单金额求和, 就可以使用集合的reduce方法累加了:

代码语言:javascript复制
$lifetimeValue = $contact->orders->reduce(function ($carry, $order) { return $carry   $order->amount; }, 0);

一对多也有反向关系,但是比一对一复杂,我们其他篇幅再展开说明。

写在最后

本文通过常用的用户,通讯录,订单,手机号等模型数据,演示了laravel模型的一对一一对多 关联的使用方法。

Happy coding :-)

0 人点赞