这个问题我很久之前就遇到过,那会最方便的解决方法是在查询条件里面加上 Model 的类名,比如 where 条件的 field=id,换成 field=Order.id 这样子,不过会影响后续接盘的人。
这里我们先复现一下这个问题,我使用了 https://raw.githubusercontent.com/hhorak/mysql-sample-db/mysql-5.7/mysqlsampledatabase.sql 作为我们的测试数据,下面我就直接贴上 Model 的代码了。
app/model/Order.php
1 | <?php |
app/model/OrderDetails.php
1 | <?php |
好了,现在我们在控制器进行查询来复现。
1 | <?php |
复现到了。
1 | SQLSTATE[42S22]: Column not found: 1054 Unknown column 'orders.orderNumber' in 'where clause' |
现在我们开始处理这个问题,因为之前有相关处理经验,所以我们直接去看 vendor/topthink/think-orm/src/db/builder/Mysql.php
文件,涉及语句的生成都在这里,我们不考虑非 MySQL 的情况。
注意 select()
这个方法,这里生成的就是查询的代码,我们来段输出看看是不是。
1 | public function select(Query $query, bool $one = false): string |
好了,确定是这里,命名已经非常清楚告诉你每一个函数的作用了,所以我们直接去看 parseWhere
这个函数。
1 | protected function parseWhere(Query $query, array $where): string |
进来后打印些日志,发现处理都来自 parseWhereItem
,我们在 parseWhereItem
里面打印些日志看看。
1 | protected function parseWhereItem(Query $query, $field, array $val, array $binds = []): string |
好了,你可以看见这里存在两个问题,第一个的 RAW 的 value 没有使用模型名称,最后一个的 key 也一样。
可能你会有疑问为什么两个都不是统一的问题,RAW 是用来处理字段和字段之间的判断问题,如果你直接使用 where 那会当普通字符串来处理。
我们先来处理下面这条语句,因为这条语句的生成在模型关联之前,所以这里我们在 parseWhereItem
里面是获取不到相关信息的。
1 | SELECT SUM(`priceEach`) AS think_sum FROM `orderdetails` `sum_table` WHERE ( `sum_table`.`orderNumber` =orders.orderNumber ) |
我们需要跳转到 parseKey()
函数,上一次我们处理 JSON 也是在这里的,这次我们需要通过强制的方式来进行对修改,所以我没必要想过要提交 PR,这里的不确定会有一些。
我们在 parseKey()
的最后来输出下返回值,看一下我们要怎么识别出这段 SQL。
1 | public function parseKey(Query $query, string|int|Raw $key, bool $strict = false): string |
嗯,我们这边选 AS think_sum FROM
作为判断条件吧,然后将 =orders.
作为替换的条件。
1 | public function parseKey(Query $query, string|int|Raw $key, bool $strict = false): string |
可以看见语句变正常了,这里已经使用上了模型名称。
1 | (SELECT SUM(`priceEach`) AS think_sum FROM `orderdetails` `sum_table` WHERE ( `sum_table`.`orderNumber` = `Order`.orderNumber )) |
现在我们回到 parseWhereItem
,我们需要在这里处理最后一个问题,这里是基础的 where 条件没有带上模型名称,我们就直接判断有没有 .
来进行处理。
1 | protected function parseWhereItem(Query $query, $field, array $val, array $binds = []): string |
好了,我们刷新已经可以查询出来数据了(记得把之前的 dump 去掉)。