源码
::merge
1 | /** |
模型集合合并的时候,如果存在相同主键值的模型,那么合并的结果中,只会有相同主键值模型的最后一个。相同主键值的模型会被忽略掉。
不同模型相同表关联的传统查询方式
对于某些场景可能要利用到这个特性。
比如有模型集合 A,里面有关联 a
, a.b
,
a.c
,我们需要加载这些关联很简单,按以下的写法写就行。
1 | $a = app(A::class)->hydrate(xx); |
现在我们有另外一个模型集合 B,也存在这些关联 a
,
a.b
, a.c
,一般情况下,我们会和集合 A 的 load
操作分开。
但是这个时候就产生了重复的查询了。比如上面,就产生了 3 个重复的查询。
去除重复查询
一种方法是,把 A 集合和 B 集合中的 a_id
拿出来合并去数据库查询。但是这样操作起来相对麻烦,查询出来还要手动组装回去。
另外一种方法是,合并两个集合 A 和 B 得到一个新的 Eloquent 集合。然后使用 Eloquent Collection 的 load 方法一次性加载关联数据。这样就可以避免很多重复查询。
1 | $c = $a->merge($b); |
为什么行得通?
因为我们操作的是模型,一个个对象,在 load 操作执行的时候会设置对应对象的属性,而新集合持有的对象和原集合的对象是一样的,所以最终的结果就是:集合 A 和集合 B 里面的对象都获取到了关联数据。
这和 merge 有什么关系?
现在有另外一种场景,我们有一个集合 A 和一个 a_id
数组,但是我们也想一次性查询出集合 A 的关联和 a_id
数组的关联数据,避免重复查询。
我的做法是,根据 a_id
数组建立另一个模型 B
的集合,其外键 a_id
的值分别为 a_id
数组里的值。
1 | $b = collect(); |
我们想要的结果是,也是没有重复查询。但是事与愿违,我们发现产生了一些重复的查询,这是为什么呢?
通过打印 $c
,发现里面只有一个 B
模型的对象,其他的都没有了。这就是本文要探讨的问题,因为这些 B
模型对象没有设置主键,其主键都是
null,最终只有一个成功合并进去,即使这些模型的 a_id
属性不一样。
破解之道
现在我们知道了原因,也就不难解决了,因为这个模型 B 其实不是我们需要的数据,我们需要的只是其查询出来的关联数据,我们就给它们不一样的主键值就行了。
1 | $key = 0; |
最后发现,没有了重复的查询。
如何拿出这些关联?
1 | $a = $b->pluck('a'); |