记一次有关thinkphp一对一关联 预载入的排序问题

目前在二开一个商城, 要修改用户申请售后的问题

当前的逻辑 ( 用户申请售后 -> 后台拒绝退款 -> 用户端无法进行操作)
要修改成的逻辑 (用户申请售后 -> 后台拒绝退款 -> 用户继续申请售后 -> 后台继续进行审核…)

因为我已经给自己的号提交过退货并且拒绝了, 目前数据库退款记录的数据ID分别是 34

1.看接口

在这里插入图片描述
前端默认查询出来的数据是按照asc进行排序
但是 后端的查询是按照 desc 来进行排序的

2.看代码

前端代码

$list   =  $this
            .... 查询条件
            ->paginate(10, false, [
                'query' => Request::instance()->request()
            ]);
        foreach($list as $v){
           // 如果是售后 则调用预载入
            if($type == 4){
                $v['sales'] = $v->sales;
            }
        }

后端代码

// 经过一系列调用  调用到了common
/**
     * 订单详情
     * @param $order_id
     * @return null|static
     * @throws \think\exception\DbException
     */
    public static function detail($order_id)
    {
        return self::get($order_id, ['sales']);
    }

在排查到sales后发现这两个都最终汇聚到了 app\common\model\Order 下的预载入 sales

预载入代码

public function sales(){
        return $this->hasOne('OrderSales','order_id','order_id');
    }

我们并没有进行排序, 但是为什么前端是正常, 但后端是按照desc 来进行排序的呢?
我试着给预载入代码里面加入排序

public function sales(){
        return $this->hasOne('OrderSales','order_id','order_id')->order("id desc");
    }

然后邪门的来了, 前端和后端的排序同时被颠倒了.

接着往下看

因为目前前端的是正常的, 后端一直是反着来. 所以我们一步一步往下查.

根据self::get() 去找到 \thinkphp\library\think\Model.php 里面的 get()

然后里面的最终代码是$query->find($data) 我们去看一下 find()这个方法

think\db\Query::find 里面找到预载入查询 $result->eagerlyResult($result, $options['with']);

接着找 think\Model::eagerlyResult 里面找到 $this->$relation()->eagerlyResult($result, $relation, $subRelation, $closure); 打印一下 $this->$relation() 打印出来 object(think\model\relation\HasOne)#83 (11) 接着去 HasOne 里面找 eagerlyResult 发现里面没有, 但是 HasOne是继承了 OneToOne

接着找 命名空间\think\model\relation\OneToOne
在这里插入图片描述
通过打印知道了走的是 IN查询
所以 接着找 think\model\relation\OneToOne::eagerlyOne
找到这里后到头了

 /**
     * 预载入关联查询(数据)
     * @param Model    $result
     * @param string   $relation
     * @param string   $subRelation
     * @param \Closure $closure
     * @return mixed
     */
abstract protected function eagerlyOne(&$result, $relation, $subRelation, $closure);

那就谁继承的这个OneToOne就去找谁 . 我们来到了 HasOne里面
果然在这里!

打印下方代码的$data 我们如愿以偿的找到了最终的数据

$data = $this->eagerlyWhere($this->query, [$foreignKey => $result->$localKey], $foreignKey, $relation, $subRelation, $closure);

那就去开盒这个eagerlyWhere 它在OneToOne

/**
     * 一对一 关联模型预查询(IN方式)
     * @access public
     * @param object        $model       关联模型对象
     * @param array         $where       关联预查询条件
     * @param string        $key         关联键名
     * @param string        $relation    关联名
     * @param string        $subRelation 子关联
     * @param bool|\Closure $closure
     * @return array
     */
    protected function eagerlyWhere($model, $where, $key, $relation, $subRelation = '', $closure = false)
    {
        $this->baseQuery = true;

        // 预载入关联查询 支持嵌套预载入
        if ($closure) {
            call_user_func_array($closure, [ & $model]);
            if ($field = $model->getOptions('with_field')) {
                $model->field($field)->removeOption('with_field');
            }
        }
        $list = $model->where($where)->with($subRelation)->select();
        // 组装模型数据
        $data = [];
        foreach ($list as $set) {
            $data[$set->$key] = $set;
        }
        return $data;
    }

最终的原因找到了, 排序都是正确的. 但是这个eagerlyWhere 会取出查询出来的最后一条数据. 所以会造成排序颠倒的问题.

解决方案

protected function eagerlyWhere($model, $where, $key, $relation, $subRelation = '', $closure = false)
    {
        $this->baseQuery = true;

        // 预载入关联查询 支持嵌套预载入
        if ($closure) {
            call_user_func_array($closure, [ & $model]);
            if ($field = $model->getOptions('with_field')) {
                $model->field($field)->removeOption('with_field');
            }
        }
        $list = $model->where($where)->with($subRelation)->select();
        // 组装模型数据
        $data = [];
        foreach ($list as $set) {
            if(empty($data[$set->$key])){
                $data[$set->$key] = $set;
            } 
        }
        return $data;
    }

将上述代码替换, 核心部分

 if(empty($data[$set->$key])){
                $data[$set->$key] = $set;
            } 
ThinkPHP6中,实现一对多关联查询的方法是使用hasMany模式。具体设置方式如下: 1. 在主表的模型中使用hasMany方法进行关联设置: ``` public function 附表名() { return $this->hasMany(附表模型::class, '外键字段', '主键字段'); } ``` 例如: ``` public function profile() { return $this->hasMany(Profile::class, 'user_id', 'id'); } ``` 2. 进行一对多关联查询: ``` $user = UserModel::find(主表录的id); return json($user->附表关联方法名); ``` 例如: ``` $user = UserModel::find(19); return json($user->profile); ``` 3. 进行数据筛选查询: ``` $user->附表关联方法名->where('条件字段', '条件操作符', '条件值'); ``` 例如: ``` $user->profile->where('id', '>=', 10); ``` 4. 使用has()方法查询满足条件的主表录: ``` UserModel::has('附表关联方法名', '条件操作符', '条件值')->select(); ``` 例如: ``` UserModel::has('profile', '>=', 2)->select(); ``` 5. 使用together()方法,在删除主表录时,同时删除关联的附表录: ``` $user = UserModel::with('附表关联方法名')->find(主表录的id); $user->together(['附表关联方法名'])->delete(); ``` 例如: ``` $user = UserModel::with('profile')->find(22); $user->together(['profile'])->delete(); ``` 以上就是在ThinkPHP6中实现一对多关联查询的方法。希望对你有所帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏范霖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值