如何将现有模型插入关系
How to insert existing model into relation
我经常有两个模特处于 1:x 关系中:
class Child extends Model
{
public function parent()
{
return $this->belongsTo(Parent::class);
}
}
现在有时我已经在一个函数中有一个相关模型的实例:
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
return $child
}
一个不同的函数将 Child
作为参数并需要 Parent
class 的属性:
function g(Child $child)
{
$child->update([
'attribute' => h($child->parent->attribute)
]);
}
现在,如果使用从 f
返回的 Child
实例调用 g,那么 Parent
实例将从数据库中检索两次。除非我们添加一个Parent
参数并将实例传递给g
,或者修改f
如下:
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->parent = $parent;
return $child
}
我更喜欢第二种方法而不是添加另一个参数,因为从中调用 g
的上下文可能无法访问 Parent
实例。而且它通常工作正常。但是,它在 g
:
中的更新语句失败
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'parent' in 'field list' (SQL: update `children`...
所以我的问题是:
有没有一种方法可以将现有模型实例插入到适当的关系中,而无需模型将分配注册为列更新?
调用 $child->parent = $parent
尝试在 $child
对象上设置 parent
field 属性。但是,您想设置 parent
relationship 属性。为此,您需要使用 setRelation()
方法:
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->setRelation('parent', $parent);
return $child;
}
但是,此时您需要注意不要创建循环引用。如果 $parent->child
关系设置为 $child
实例,然后将 $child->parent
关系设置为 $parent
实例,则您创建了一个循环引用,该循环引用将被破坏如果您尝试将任一实例转换为 json(或数组)。
也就是说,如果 $parent->child->parent === $parent
,则存在循环引用,为此创建 json/array 将是一个无限循环。
在这种情况下,如果您想格外小心,可以使用withoutRelations()
方法将关系分配给父级的克隆,不会加载任何关系。
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->setRelation('parent', $parent->withoutRelations());
return $child;
}
此后,$parent->is($parent->child->parent)
为真,$parent->child->parent === $parent
为假,无循环引用。
我经常有两个模特处于 1:x 关系中:
class Child extends Model
{
public function parent()
{
return $this->belongsTo(Parent::class);
}
}
现在有时我已经在一个函数中有一个相关模型的实例:
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
return $child
}
一个不同的函数将 Child
作为参数并需要 Parent
class 的属性:
function g(Child $child)
{
$child->update([
'attribute' => h($child->parent->attribute)
]);
}
现在,如果使用从 f
返回的 Child
实例调用 g,那么 Parent
实例将从数据库中检索两次。除非我们添加一个Parent
参数并将实例传递给g
,或者修改f
如下:
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->parent = $parent;
return $child
}
我更喜欢第二种方法而不是添加另一个参数,因为从中调用 g
的上下文可能无法访问 Parent
实例。而且它通常工作正常。但是,它在 g
:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'parent' in 'field list' (SQL: update `children`...
所以我的问题是:
有没有一种方法可以将现有模型实例插入到适当的关系中,而无需模型将分配注册为列更新?
调用 $child->parent = $parent
尝试在 $child
对象上设置 parent
field 属性。但是,您想设置 parent
relationship 属性。为此,您需要使用 setRelation()
方法:
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->setRelation('parent', $parent);
return $child;
}
但是,此时您需要注意不要创建循环引用。如果 $parent->child
关系设置为 $child
实例,然后将 $child->parent
关系设置为 $parent
实例,则您创建了一个循环引用,该循环引用将被破坏如果您尝试将任一实例转换为 json(或数组)。
也就是说,如果 $parent->child->parent === $parent
,则存在循环引用,为此创建 json/array 将是一个无限循环。
在这种情况下,如果您想格外小心,可以使用withoutRelations()
方法将关系分配给父级的克隆,不会加载任何关系。
function f(Parent $parent): Child
{
// ...
$child = $parent->createChild();
// ...
$child->setRelation('parent', $parent->withoutRelations());
return $child;
}
此后,$parent->is($parent->child->parent)
为真,$parent->child->parent === $parent
为假,无循环引用。