具体情况大概是这样的,我们有一个 MySQL 的模型,有一个 Mongo
的模型,然后在 MySQL 的模型中 hasOne Mongo 的模型,结果:
MySQL with 的时候可以查询出数据,但是使用 whereHas
的时候查询不到数据了。
环境
laravel/lumen-framework
: 5.5.2
jenssegers/mongodb
: 3.3.2
重现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class A extends \Illuminate\Database\Eloquent\Model { use \Jenssegers\Mongodb\Eloquent\HybridRelations;
public function b() { return $this->hasOne(B::class, '_id', 'b_id'); } }
class B extends \Jenssegers\Mongodb\Eloquent\Model { }
|
Laravel 的关联查询如下:
1 2 3 4 5 6 7
| $a = A::query()->with('b')->whereKey(10)->first();
dump($a);
$a = A::query()->whereHas('b')->whereKey(10)->first();
dump($a);
|
正常情况下,其实第二个查询我们也应该查询出来才对,可是我们查不到,然后尝试打印一下查询:
1 2 3 4
| [2021-06-08 09:54:30] lumen.INFO: time: 75.18 select * from `as` where `as`.`id` = 10 limit 1 [2021-06-08 09:54:30] lumen.INFO: time: 48.25, connection: mongo_core, db.bs.find({"_id":{"$in":["60becd2306bce821e55ffce3"]}}) [2021-06-08 09:54:30] lumen.INFO: time: 2.52, connection: mongo_core, db.bs.find({"projection":{"_id":true}}) [2021-06-08 09:54:30] lumen.INFO: time: 18.81 select * from `as` where `id` in ("60becd2306bce821e55ffce3") and `as`.`id` = 10 limit 1
|
我们发现最后一条语句并不是如我们期待的那样,where b_id in
而是
where id in
,这是一个不正常的行为,因为根据我们的定义,关联
A 模型的字段应该是 b_id
而不是 id
。
原因
因为想找到查询使用 id
而不是
b_id
,对关联部分的代码 debug 了一下,最后发现,位于
\Jenssegers\Mongodb\Helpers\QueriesRelationships
的方法
getRelatedConstraintKey
返回了一个错误的关联键:
QueriesRelationships.php
v3.3.2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
protected function getRelatedConstraintKey($relation) { if ($relation instanceof HasOneOrMany) { return $this->model->getKeyName(); }
if ($relation instanceof BelongsTo) { return $relation->getForeignKey(); }
throw new \Exception(class_basename($relation) . ' Is Not supported for hybrid query constraints!'); }
|
感觉这是一个
bug,然后去新版本的库里面看了一下,发现新版本里面已经修改过来了:
QueriesRelationships.php
v3.7.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
protected function getRelatedConstraintKey(Relation $relation) { if ($relation instanceof HasOneOrMany) { return $relation->getLocalKeyName(); }
if ($relation instanceof BelongsTo) { return $relation->getForeignKeyName(); }
if ($relation instanceof BelongsToMany && !$this->isAcrossConnections($relation)) { return $this->model->getKeyName(); }
throw new Exception(class_basename($relation) . ' is not supported for hybrid query constraints.'); }
|
结论
由于修复的版本与当前使用的版本相差太多,而且依赖于 Laravel
的版本,所以无法升级其版本,只有换一种写法了。(whereHas
拆分出来,先查询到关联数据的 _id,然后作为 whereIn 条件传递)。