【问题标题】:Accessing Parent relations Laravel访问父关系 Laravel
【发布时间】:2015-04-14 18:02:21
【问题描述】:

我有一种情况,我需要遍历模型关系(一对多)并在孩子身上调用一个函数。即

$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);
}

由于所有的孩子都有相同的父母,这将缓存查询,并避免为每个孩子调用它。这似乎是这 3 种解决方案中最好的,但我不喜欢让这成为关系中的强制性内容。

有没有更好的方法我没有考虑?也许一个更好的地方包含记忆功能?

谢谢你,-沃利

【问题讨论】:

    标签: php laravel-4 eloquent eager-loading


    【解决方案1】:

    如果您定义了反向关系,您可以执行以下操作:

    $parent = ParentClass::find(1);
    foreach ($parent->children as $child) {
        $requiredParentAttr = $parent->attr;
        $child->function($requiredParentAttr);
        // whatever else
    }
    

    【讨论】:

    • 我发布了一个简化的示例,该功能依赖于父级的许多属性。此外,在您的示例中,您不需要通过 $child-parent->attr,因为 $parent 仍在范围内,您可以简单地执行 $requiredAttr = $parent->attr;
    【解决方案2】:

    我想我找到了一个我满意的解决方案。对我来说仍然没有“雄辩”的感觉,但我认为可能没有更好的解决方案,(尽管可以证明我错了。)

    foreach($children as $child)
    {
        $child->parent = $parent;
        $child->function();
    }
    

    由于我们已经有了父对象,只需将父对象作为对每个子对象的引用即可。这避免了任何内存问题。这甚至比 remember() 选项更好,因为它从不为父项执行第二次查询。这使方法签名保持干净和合乎逻辑。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-13
      • 1970-01-01
      • 1970-01-01
      • 2020-07-03
      • 2017-02-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多