问题描述
- 在远程一对一查询用 hasWhere() 进行关联模型的条件查询时,可能会出现报错 无法查询的问题,例如下图
问题分析
由于hasOneThrough 是继承 hasManyThrough,因此会直接使用 hasManyThrough 中的
hasWhere() 方法,
/**
* 根据关联条件查询当前模型
* @access public
* @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @param string $joinType JOIN类型
* @param Query $query Query对象
* @return Query
*/
public function hasWhere($where = [], $fields = null, $joinType = '', Query $query = null): Query
{
$model = Str::snake(class_basename($this->parent));
$throughTable = $this->through->getTable();
$pk = $this->throughPk;
$throughKey = $this->throughKey;
$modelTable = (new $this->model)->getTable();
if (is_array($where)) {
$this->getQueryWhere($where, $modelTable);
} elseif ($where instanceof Query) {
$where->via($modelTable);
} elseif ($where instanceof Closure) {
$where($this->query->via($modelTable));
$where = $this->query;
}
$fields = $this->getRelationQueryFields($fields, $model);
$softDelete = $this->query->getOptions('soft_delete');
$query = $query ?: $this->parent->db();
return $query->alias($model)
->join($throughTable, $throughTable . '.' . $this->foreignKey . '=' . $model . '.' . $this->localKey)
->join($modelTable, $modelTable . '.' . $throughKey . '=' . $throughTable . '.' . $this->throughPk, $joinType)
->when($softDelete, function ($query) use ($softDelete, $modelTable) {
$query->where($modelTable . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
})
->group($modelTable . '.' . $this->throughKey)
->where($where)
->field($fields);
}
- 这可能不适用于我们的 远程一对一 hasOneThrough 的使用,因此需要修改一下
解决方法
这里直接拷贝上面hasManyThrough 的 hasWhere() 方法到 hasOneTrough,具体文件路径如下
- hasManyThrough: vendor\topthink\think-orm\src\model\relation\HasManyThrough.php
- hasOneThrough: vendor\topthink\think-orm\src\model\relation\HasOneThrough.php
接下来修改hasOneThrough 里刚刚复制的 hasWhere 方法,或者直接复制下面修改好的方法也可以
/**
* 根据关联条件查询当前模型
* @access public
* @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @param string $joinType JOIN类型
* @param Query $query Query对象
* @return Query
*/
public function hasWhere($where = [], $fields = null, $joinType = '', Query $query = null): Query
{
$model = Str::snake(class_basename($this->parent)); // "当前模型"
$throughTable = $this->through->getTable(); // "中间模型"
$pk = $this->throughPk;
$throughKey = $this->throughKey;
$modelTable = (new $this->model)->getTable(); // "关联模型"
if (is_array($where)) {
$this->getQueryWhere($where, $modelTable);
} elseif ($where instanceof Query) {
$where->via($modelTable);
} elseif ($where instanceof Closure) {
$where($this->query->via($modelTable));
$where = $this->query;
}
$fields = $this->getRelationQueryFields($fields, $model);
$softDelete = $this->query->getOptions('soft_delete');
$query = $query ?: $this->parent->db();
// start 修改的地方
$alias = [
$throughTable => $throughTable, // "中间模型"
$modelTable => $modelTable, // "关联模型"
$model => $model // "当前模型"
];
return $query
->alias($alias) // 这里替换掉原来的$model, 这是为了解决开头的那个报错问题
->join($throughTable, $throughTable . '.' . $this->foreignKey . '=' . $model . '.' . $this->localKey)
->join($modelTable, $modelTable . '.' . $throughKey . '=' . $throughTable . '.' . $this->throughPk, $joinType)
->when($softDelete, function ($query) use ($softDelete, $modelTable) {
$query->where($modelTable . strstr($softDelete[0], '.'), '=' == $softDelete[1][0] ? $softDelete[1][1] : null);
})
// ->group($modelTable . '.' . $this->throughKey) // 这里group的分组我们也用不到
->where($where);
// ->field($fields); // 这里去掉即可,我感觉没什么用,毕竟字段控制可以直接用visible控制
// end
}
这里说下修改的地方(虽然代码里写明,但不排除有不看的0_0)
-
修改1:将原来的$model 替换成 $alias(对应参数“中间模型”,“关联模型”, “当前模型”)
-
修改2:其实也没啥修改的,也就去掉了点不要的(group 和 field)
-
修改前
-
修改后
到这就可以正常的使用hasWhere对关联模型的字段进行查询了,如有错漏,欢迎评论指正0_0