远程一对一关系
远程一对一关联通过一个中间关联模型实现。
例如,如果每个供应商都有一个用户,并且每个用户与一个用户历史记录相关联,那么供应商可以通过用户访问用户的历史记录,让我们看看定义这种关系所需的数据库表:
users
id - integer
supplier_id - integer
suppliers
id - integer
history
id - integer
user_id - integer
虽然 history 表不包含 supplier_id ,但 hasOneThrough 关系可以提供对用户历史记录的访问,以访问供应商模型。
现在我们已经检查了关系的表结构,让我们在 Supplier 模型上定义相应的方法:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Supplier extends Model{ /** * 用户的历史记录。 */ public function userHistory() { return $this->hasOneThrough('App\History', 'App\User'); } }
/**
* //Supplier
* //return $this->hasOneThrough('App\History', 'App\User','supplier_id','user_id','id','id');
*
* 当执行关联查询时,通常会使用 Eloquent 约定的外键名。
* 如果你想要自定义关联的键,可以通过给 hasOneThrough
* 传递给 hasOneThrough 方法的
* 第一个参数是希望访问的模型名称,
* 第二个参数是中间模型的名称。
* 方法传递第三个和第四个参数实现,
* 第三个参数表示中间模型的外键名,
* 第四个参数表示最终模型的外键名。
* 第五个参数表示本地键名,
* 而第六个参数表示中间模型的本地键名:
* 'App\History',
* 'App\User',
* 'supplier_id', // 用户表外键
* 'user_id', // 历史记录表外键
* 'id', // 供应商本地键
* 'id' // 用户本地键
**/
举例说明:
通过order模型找到医生等级:
class OrderModel extends Model{ public function clinicDoctorLevel() { return $this->hasOneThrough(DoctorLevelModel::class, DoctorModel::class, 'id', 'id', 'clinic_doctor_id', 'doctor_level' ); } }
表结构:
order
id
clinic_doctor_id fk doctor.id
doctor
id
doctor_level fk doctor_level.id
doctor_level
id
level_name
现在通过order 的一个id ,通过clinic_doctor_id 医生关联的doctor表 找到医生等级
/**
* 第一个参数是希望访问的模型名称, 需要寻找 DoctorLevel
* 第二个参数是中间模型的名称。 通过Doctor
* 方法传递第三个和第四个参数实现,
* 第三个参数表示中间模型的外键名, id (目标)
* 第四个参数表示最终模型的外键名。 id (目标)
* 第五个参数表示本地键名, clinic_doctor_id 与第三个参数的id对应 先找到中间模型关联关系 中间模型关联关系 当前模型clinic_doctor_id与doctor表中id对应
* 而第六个参数表示中间模型的本地键名: doctor_level 与第四个参数的id对应 最终模型关联关系 doctor表中doctor_level与doctor_level中id对应
**/
调用关联模型关联,使用with
with中可以使用键值对的形式,采用回调的方式进行数据获取。
use Illuminate\Database\Eloquent\Builder;
'with'=>function(Builder $query){
$query->select('');
}
前边使用 builder以后,就能有代码提示功能了。
/** * orderInfo * @param int $id * @param array $fields * @return array * * @date 2020/1/15 18:57 */ public function orderInfo(int $id, array $fields = []) { $fields || $fields = '*'; return OutPatientOrderModel::getQuery()->with([ 'detail' => function (Builder $query) { $query->where('is_deleted', '0')->select('img_des', 'illness_des', 'order_id', 'pkid', 'is_visit'); }, 'clinicDoctorLevel' => function (Builder $query) { $query->select('doctor_level.level_name','doctor_level.id as levelId'); } ])->findOrNew($id, $fields)->toArray(); }
远程一对多关联
远程「一对多」关联提供了方便、简短的方式通过中间的关联来获得远层的关联。
例如,一个 Country 模型可以通过中间的 User 模型获得多个 Post 模型。
在这个例子中,你可以轻易地收集给定国家的所有博客文章。让我们来看看定义这种关联所需的数据表:
countries
id - integer
name - string
users
id - integer
country_id - integer
name - string
posts
id - integer
user_id - integer
title - string
虽然 posts 表中不包含 country_id 字段,但 hasManyThrough 关联能让我们通过 $country->posts 访问到一个国家下所有的用户文章。为了完成这个查询,Eloquent 会先检查中间表 users 的 country_id 字段,找到所有匹配的用户 ID 后,使用这些 ID,在 posts 表中完成查找。
现在,我们已经知道了定义这种关联所需的数据表结构,接下来,让我们在 Country 模型中定义它:
class Country extends Model{ public function posts() { return $this->hasManyThrough( 'App\Post', 'App\User', 'country_id', // 国家表外键 'user_id', // 用户表外键 'id', // 国家表本地键 'id' // 用户表本地键 ); }}
hasManyThrough 方法的第一个参数是我们最终希望访问的模型名称,而第二个参数是中间模型的名称。
当执行关联查询时,通常会使用 Eloquent 约定的外键名。如果你想要自定义关联的键,
可以通过给 hasManyThrough 方法传递第三个和第四个参数实现,第三个参数表示中间模型的外键名,
第四个参数表示最终模型的外键名。第五个参数表示本地键名,而第六个参数表示中间模型的本地键名。
下图提供两个远程一对一、一对多 模型关联示例: