我有一种情况需要遍历模型关系(1到多个)并在子项上调用函数。即。
$parent = ParentClass::find(1)
$children = $parent->children;
foreach($children as $child)
{
$child->function();
}
子内部的函数需要访问父模型中的字段。即。
public function function()
{
if($this->parent->attribute)
return "True!";
return "False";
}
如上所述执行此操作,最终会出现N + 1查询问题。每个孩子最终执行“SELECT * FROM parents WHERE id = 1”。
我有3个关于如何解决这个问题的想法,虽然其中有两个感觉很糟糕,而最后一个对我来说似乎不太好,所以我问是否有比这更好的解决方案考虑过了吗?
解决方案1:将父级加载到子模型上。即。
...
$children = $parent->children;
$children->load('parent');
foreach($children as $child)
...
我认为很明显为什么这会很糟糕,这将是一个巨大的记忆力,让父模型在内存中存储N + 1次。
解决方案2:将父母作为参数传递给孩子,即
...
foreach($children as $child)
{
$child->function($parent);
}
...
避免1的内存问题,但它仍然感觉很难看。我认为孩子应该知道它的父母,而不需要通过方法args告诉它。
解决方案3:将remember()添加到孩子的父母关系,即
public function parent()
{
return $this->hasOne('Parent')->remember(1);
}
由于所有子节点都具有相同的父节点,因此将缓存查询,并避免为每个子节点调用它。这似乎是这三种解决方案中最好的,但我不喜欢这种关系成为强制性的想法。
有没有更好的方法,我不考虑?也许是一个更好的地方来包含记忆功能?
谢谢,-Wally
答案 0 :(得分:0)
如果您定义了反向关系,您可以执行以下操作:
$parent = ParentClass::find(1);
foreach ($parent->children as $child) {
$requiredParentAttr = $parent->attr;
$child->function($requiredParentAttr);
// whatever else
}
答案 1 :(得分:0)
我想我找到了一个我满意的解决方案。仍然没有感觉到#34; Eloquent"对我来说,但我不认为这可能是一个更好的解决方案,(尽管我可以自由地证明我错了。)
foreach($children as $child)
{
$child->parent = $parent;
$child->function();
}
由于我们已经有了父对象,所以只需将父对象作为对每个子对象的引用。这可以避免任何内存问题。这甚至比remember()选项更好,因为它永远不会对父进行第二次查询。这使方法签名保持清洁和合理。