我一直在构建一个中型应用程序,现在正在启用大量的二次使用案例。这意味着更多地依赖事件和侦听器,并在单个请求中多次触摸对象。
在这个过程中,有一些案例让我对Eloquent关系的行为感到惊讶。显然,当我接收一个对象作为事件处理程序的参数时,我可能不知道它的详细历史,所以我需要了解何时/如何依赖它(以及何时/如何不对)。
在这种情况下我有一个父实体和一些孩子。这是父母的雄辩关系:
public function children()
{
return $this->hasMany(Model\Child::class);
}
在父母的其他地方我有一个添加孩子的方法,如下所示:
public function addChildren(array $data)
{
$children = [];
foreach ($data as $child) {
$children[] = new Child($child);
}
$this->children()->saveMany($children);
}
在请求周期的后期,我正在测试父项的一些条件,并且在真实的情况下,我让孩子们使用$parent->children
,并进一步使用它们。
在有人指出我错过的商业规则之前,情况正常。如果父母已经有孩子,你就不能以这种方式增加孩子。为了解决这个问题,我在addChildren()
方法的顶部进行了一个简单的测试:
public function addChildren(array $data)
{
if(count($this->children)) {
throw new \Exception('Can not add children where they already exist');
}
// remainder of the method goes here...
}
当我添加此代码时,我开始得到意想不到的结果。经过调查,我发现通过在方法的早期对儿童进行计数(这显然意识到这种关系),它影响了这种关系在以后的行为方式。
我尝试在运行方法后转储$parent->children
的值。如果我排除首先计算孩子的代码,我会得到我期望的 - 我新添加的孩子的集合。但是,如果我包含计数代码,我会得到一个空数组。
所以,问题是:
我非常喜欢Laravel,所以我很想理解这个炙手可热的问题......
编辑:
对于正在阅读这篇文章的人来说,我最终排队了一些用例的非核心部分。这对性能来说是一个很好的举动,并且在解耦方面感觉很好。因为Laravel序列化了Eloquent模型id(而不是模型本身),它以合理优雅的方式给了我正在寻找的效果。
答案 0 :(得分:2)
不,你没有以错误的方式使用关系,你也没有期待太多。
有了REST的想法,大部分时间你都不应该发现自己处于想要加载关系,添加关系然后返回新关系的情况。如果您有商店或更新路线,那么您不需要事先加载关系(除非您有特定用例),其余时间您应该只是调用关系并返回结果。
如果出于某种原因,你需要修改关系(我确定有很多理由),然后返回结果,你可以随时重新加载关系,例如。
$parent->fresh('children');
或者,如果您只想计算孩子的数量,则可以使用计数查询而不是获取所有children
:
$parent->children()->count();
这不会加载关系,但会告诉您有多少孩子。