引言
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 :-)