作为程序员一定要保持良好的睡眠,才能好编程

laravel关联模型之远程一对一/一对多

发布时间:2021-05-26




远程一对一关系

远程一对一关联通过一个中间关联模型实现。

例如,如果每个供应商都有一个用户,并且每个用户与一个用户历史记录相关联,那么供应商可以通过用户访问用户的历史记录,让我们看看定义这种关系所需的数据库表:


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对应

**/



image.png



调用关联模型关联,使用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 方法传递第三个和第四个参数实现,第三个参数表示中间模型的外键名,

第四个参数表示最终模型的外键名。第五个参数表示本地键名,而第六个参数表示中间模型的本地键名。



下图提供两个远程一对一、一对多 模型关联示例:


image.png



image.png



image.png