从ThinkPHP6.0.2升级到ThinkPHP6.0.3后,测试整体网站,发现用了多对多关联关联统计的地方均报错SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'pivot'。经过排查,系think-orm扩展最近一次的升级,调整了多对多关联导致的错误。

应用代码

下面是关键代码部分

控制器

\app\model\TaskLabel::withCount(['task'])->select()

TaskLabel模型

<?php
namespace app\model;

use think\Model;

/**
 * 任务标签模型
 * @package app\model
 */
class TaskLabel extends Model
{
    // 自动写入时间
    protected $autoWriteTimestamp = 'timestamp';

    // 关闭更新时间
    protected $updateTime = false;

    /**
     * 任务关联
     * @return \think\model\relation\BelongsToMany
     */
    public function task()
    {
        return $this->belongsToMany(Task::class, TaskLabelPivot::class, 'task_id', 'label_id')
            ->where('status', '>', 0);
    }
}

中间表模型

<?php
namespace app\model;

use think\model\Pivot;

/**
 * 任务标签中间表模型
 * @package app\model
 */
class TaskLabelPivot extends Pivot
{
    // 自动写入时间
    protected $autoWriteTimestamp = 'timestamp';

    // 关闭更新时间
    protected $updateTime = false;
}

任务模型

<?php
namespace app\model;

use think\Model;

/**
 * 任务
 * @package app\model
 */
class Task extends Model
{
    // 自动写入时间
    protected $autoWriteTimestamp = 'timestamp';
}

流程解刨

1.执行withCount方法

\think\db\BaseQuery::withCount()

2.执行withAggregate方法

\think\db\BaseQuery::withAggregate()

3.执行relationCount方法

\think\Model::relationCount()

4.执行task方法

\app\model\TaskLabel::task()

5.触发__call方法

因为where是Query里面的方法,在关联类里面不存在,所以会触发魔术方法

\think\model\Relation::__call()

6.执行baseQuery方法

\think\model\relation\BelongsToMany::baseQuery()

7.执行belongsToManyQuery方法

这方法里面会调用Query类的fieldjoinwhere等方法

\think\model\relation\BelongsToMany::belongsToManyQuery()

8.执行getRelationCountQuery方法

\think\model\relation\BelongsToMany::getRelationCountQuery()

9.执行belongsToManyQuery方法

这方法里面会调用Query类的fieldjoinwhere等方法

\think\model\relation\BelongsToMany::belongsToManyQuery()

问题总结

从执行流程可以看出,\think\model\relation\BelongsToMany::belongsToManyQuery()执行了两次,导致的结果就是join也执行了两次,出现了开头的报错SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'pivot'

belongsToManyQuery为什么会执行两次呢?
主要原因就是我在关联方法里面使用了where方法,这个方法是Query类的,在关联类里面不存在,所以会触发魔术方法。
而魔术方法里会执行baseQuerybaseQuery又会执行belongsToManyQuerygetRelationCountQuery也会执行belongsToManyQuery。就这样,join重复了。

问题已找到,关联方法后面不能跟着Query类的方法,否则就会出错。目前尚不清楚是框架的问题还是自己的用法问题,但框架问题的可能性大些,毕竟用法按照手册也报错。

解决办法

虽然找问题的时间很长,但最终的解决办法也很简单,只需要将think-orm扩展降级即可。

composer require topthink/think-orm:v2.0.32

好了,散了散了,该干嘛干嘛去。等官方出结果

2020-07-15:目前最新开发版已修复该问题,除了降级,我们还可以使用下列命令升级到最新开发版。

composer require topthink/think-orm:2.0.x-dev

其它

下面是完整的执行流程记录,备份记录下吧

array(9) {
  [0]=>
  array(5) {
    ["file"]=>
    string(63) "/vendor/topthink/think-orm/src/model/relation/BelongsToMany.php"
    ["line"]=>
    int(687)
    ["function"]=>
    string(18) "belongsToManyQuery"
    ["class"]=>
    string(34) "think\model\relation\BelongsToMany"
    ["type"]=>
    string(2) "->"
  }
  [1]=>
  array(5) {
    ["file"]=>
    string(49) "/vendor/topthink/think-orm/src/model/Relation.php"
    ["line"]=>
    int(249)
    ["function"]=>
    string(9) "baseQuery"
    ["class"]=>
    string(34) "think\model\relation\BelongsToMany"
    ["type"]=>
    string(2) "->"
  }
  [2]=>
  array(5) {
    ["file"]=>
    string(24) "/app/model/TaskLabel.php"
    ["line"]=>
    int(25)
    ["function"]=>
    string(6) "__call"
    ["class"]=>
    string(20) "think\model\Relation"
    ["type"]=>
    string(2) "->"
  }
  [3]=>
  array(5) {
    ["file"]=>
    string(61) "/vendor/topthink/think-orm/src/model/concern/RelationShip.php"
    ["line"]=>
    int(392)
    ["function"]=>
    string(4) "task"
    ["class"]=>
    string(19) "app\model\TaskLabel"
    ["type"]=>
    string(2) "->"
  }
  [4]=>
  array(5) {
    ["file"]=>
    string(64) "/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php"
    ["line"]=>
    int(273)
    ["function"]=>
    string(13) "relationCount"
    ["class"]=>
    string(11) "think\Model"
    ["type"]=>
    string(2) "->"
  }
  [5]=>
  array(5) {
    ["file"]=>
    string(64) "/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php"
    ["line"]=>
    int(325)
    ["function"]=>
    string(13) "withAggregate"
    ["class"]=>
    string(18) "think\db\BaseQuery"
    ["type"]=>
    string(2) "->"
  }
  [6]=>
  array(3) {
    ["function"]=>
    string(9) "withCount"
    ["class"]=>
    string(18) "think\db\BaseQuery"
    ["type"]=>
    string(2) "->"
  }
  [7]=>
  array(3) {
    ["file"]=>
    string(40) "/vendor/topthink/think-orm/src/Model.php"
    ["line"]=>
    int(1047)
    ["function"]=>
    string(20) "call_user_func_array"
  }
  [8]=>
  array(5) {
    ["file"]=>
    string(24) "/app/controller/Task.php"
    ["line"]=>
    int(573)
    ["function"]=>
    string(12) "__callStatic"
    ["class"]=>
    string(11) "think\Model"
    ["type"]=>
    string(2) "::"
  }
}
array(7) {
  [0]=>
  array(5) {
    ["file"]=>
    string(63) "/vendor/topthink/think-orm/src/model/relation/BelongsToMany.php"
    ["line"]=>
    int(379)
    ["function"]=>
    string(18) "belongsToManyQuery"
    ["class"]=>
    string(34) "think\model\relation\BelongsToMany"
    ["type"]=>
    string(2) "->"
  }
  [1]=>
  array(5) {
    ["file"]=>
    string(61) "/vendor/topthink/think-orm/src/model/concern/RelationShip.php"
    ["line"]=>
    int(392)
    ["function"]=>
    string(21) "getRelationCountQuery"
    ["class"]=>
    string(34) "think\model\relation\BelongsToMany"
    ["type"]=>
    string(2) "->"
  }
  [2]=>
  array(5) {
    ["file"]=>
    string(64) "/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php"
    ["line"]=>
    int(273)
    ["function"]=>
    string(13) "relationCount"
    ["class"]=>
    string(11) "think\Model"
    ["type"]=>
    string(2) "->"
  }
  [3]=>
  array(5) {
    ["file"]=>
    string(64) "/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php"
    ["line"]=>
    int(325)
    ["function"]=>
    string(13) "withAggregate"
    ["class"]=>
    string(18) "think\db\BaseQuery"
    ["type"]=>
    string(2) "->"
  }
  [4]=>
  array(3) {
    ["function"]=>
    string(9) "withCount"
    ["class"]=>
    string(18) "think\db\BaseQuery"
    ["type"]=>
    string(2) "->"
  }
  [5]=>
  array(3) {
    ["file"]=>
    string(40) "/vendor/topthink/think-orm/src/Model.php"
    ["line"]=>
    int(1047)
    ["function"]=>
    string(20) "call_user_func_array"
  }
  [6]=>
  array(5) {
    ["file"]=>
    string(24) "/app/controller/Task.php"
    ["line"]=>
    int(573)
    ["function"]=>
    string(12) "__callStatic"
    ["class"]=>
    string(11) "think\Model"
    ["type"]=>
    string(2) "::"
  }
}

标签: none

添加新评论