从ThinkPHP6.0.2升级到ThinkPHP6.0.3后,测试整体网站,发现用了多对多关联关联统计的地方均报错SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'pivot'
。经过排查,系think-orm扩展最近一次的升级,调整了多对多关联导致的错误。
应用代码
下面是关键代码部分
控制器
代码语言:javascript复制appmodelTaskLabel::withCount(['task'])->select()
TaskLabel模型
代码语言:javascript复制<?php
namespace appmodel;
use thinkModel;
/**
* 任务标签模型
* @package appmodel
*/
class TaskLabel extends Model
{
// 自动写入时间
protected $autoWriteTimestamp = 'timestamp';
// 关闭更新时间
protected $updateTime = false;
/**
* 任务关联
* @return thinkmodelrelationBelongsToMany
*/
public function task()
{
return $this->belongsToMany(Task::class, TaskLabelPivot::class, 'task_id', 'label_id')
->where('status', '>', 0);
}
}
中间表模型
代码语言:javascript复制<?php
namespace appmodel;
use thinkmodelPivot;
/**
* 任务标签中间表模型
* @package appmodel
*/
class TaskLabelPivot extends Pivot
{
// 自动写入时间
protected $autoWriteTimestamp = 'timestamp';
// 关闭更新时间
protected $updateTime = false;
}
任务模型
代码语言:javascript复制<?php
namespace appmodel;
use thinkModel;
/**
* 任务
* @package appmodel
*/
class Task extends Model
{
// 自动写入时间
protected $autoWriteTimestamp = 'timestamp';
}
流程解刨
1.执行withCount方法
代码语言:javascript复制thinkdbBaseQuery::withCount()
2.执行withAggregate方法
代码语言:javascript复制thinkdbBaseQuery::withAggregate()
3.执行relationCount方法
代码语言:javascript复制thinkModel::relationCount()
4.执行task方法
代码语言:javascript复制appmodelTaskLabel::task()
5.触发__call方法
因为where是Query
里面的方法,在关联类里面不存在,所以会触发魔术方法
thinkmodelRelation::__call()
6.执行baseQuery方法
代码语言:javascript复制thinkmodelrelationBelongsToMany::baseQuery()
7.执行belongsToManyQuery方法
这方法里面会调用Query
类的field
、join
、where
等方法
thinkmodelrelationBelongsToMany::belongsToManyQuery()
8.执行getRelationCountQuery方法
代码语言:javascript复制thinkmodelrelationBelongsToMany::getRelationCountQuery()
9.执行belongsToManyQuery方法
这方法里面会调用Query
类的field
、join
、where
等方法
thinkmodelrelationBelongsToMany::belongsToManyQuery()
问题总结
从执行流程可以看出,thinkmodelrelationBelongsToMany::belongsToManyQuery()
执行了两次,导致的结果就是join
也执行了两次,出现了开头的报错SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'pivot'
belongsToManyQuery
为什么会执行两次呢?
主要原因就是我在关联方法里面使用了where
方法,这个方法是Query类的,在关联类里面不存在,所以会触发魔术方法。
而魔术方法里会执行baseQuery
,baseQuery
又会执行belongsToManyQuery
。getRelationCountQuery
也会执行belongsToManyQuery
。就这样,join
重复了。
问题已找到,关联方法后面不能跟着Query
类的方法,否则就会出错。目前尚不清楚是框架的问题还是自己的用法问题,但框架问题的可能性大些,毕竟用法按照手册也报错。
解决办法
虽然找问题的时间很长,但最终的解决办法也很简单,只需要将think-orm
扩展降级即可。
composer require topthink/think-orm:v2.0.32
好了,散了散了,该干嘛干嘛去。等官方出结果
2020-07-15:目前最新开发版已修复该问题,除了降级,我们还可以使用下列命令升级到最新开发版。
代码语言:javascript复制composer require topthink/think-orm:2.0.x-dev
其它
下面是完整的执行流程记录,备份记录下吧
代码语言:javascript复制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) "thinkmodelrelationBelongsToMany"
["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) "thinkmodelrelationBelongsToMany"
["type"]=>
string(2) "->"
}
[2]=>
array(5) {
["file"]=>
string(24) "/app/model/TaskLabel.php"
["line"]=>
int(25)
["function"]=>
string(6) "__call"
["class"]=>
string(20) "thinkmodelRelation"
["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) "appmodelTaskLabel"
["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) "thinkModel"
["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) "thinkdbBaseQuery"
["type"]=>
string(2) "->"
}
[6]=>
array(3) {
["function"]=>
string(9) "withCount"
["class"]=>
string(18) "thinkdbBaseQuery"
["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) "thinkModel"
["type"]=>
string(2) "::"
}
}
代码语言:javascript复制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) "thinkmodelrelationBelongsToMany"
["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) "thinkmodelrelationBelongsToMany"
["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) "thinkModel"
["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) "thinkdbBaseQuery"
["type"]=>
string(2) "->"
}
[4]=>
array(3) {
["function"]=>
string(9) "withCount"
["class"]=>
string(18) "thinkdbBaseQuery"
["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) "thinkModel"
["type"]=>
string(2) "::"
}
}