预加载 hasMany & belongsTo(循环 reference/infinite 循环)
Eager load hasMany & belongsTo (circular reference/infinite loop)
更新(解决方案)
- 如果您需要
$user->images
中的 $image
之一的 ->user
关系,那么 $user
变量已经可用,因为您加载了 ->images
它!
- 不要使用
protected $with
Eloquent 属性。这是一个反模式。
- 而不是明确地从 where/when 按需加载关系是需要的(注意:它不应该阻止你保持干爽!)
- 如果你真的need/want,请看@nicksonyap 的回答。它可以解决问题(我相信——未经测试)。
原创
我 运行 我认为这是一个简单的问题:
- 我有一个
User
对象 有很多 Image
s
Image
属于User
...(反比关系)
我的问题是我想同时加载 User
模型上的 images()
和 Image
模型上的 user()
。为此,我只是按照文档中的说明设置了 $with
属性。
我的User
模特:
class User extends EloquentModel {
protected $with = ['images'];
public function images()
{
return $this->hasMany(Image::class);
}
}
我的Image
模特:
class Image extends EloquentModel {
protected $with = ['user'];
public function user()
{
return $this->belongsTo(User::class);
}
}
但是表演时:
$user = User::find(203);
这会导致无限循环(php 分段错误)。一定有某种我找不到的循环引用:
[1] 85728 segmentation fault
编辑 2016/02
这是我发现的最简单的"Workaround":
// User.php
public function setRelation($relation, $value)
{
if ($relation === 'images') {
foreach ($value as $image) {
$image->setUser($this);
}
}
return parent::setRelation($relation, $value);
}
当您尝试查找 属性 时,那个 属性 eager 加载它拥有的所有图像,并且每个 Image eager 加载它所属的 属性,即 属性 你试图找到,它将再次开始急切加载它拥有的所有图像。等...
我解决这个问题的方法是不在模型内部进行预加载,而是在调用模型时进行预加载。
所以使用以下内容:
$prop = Property::with('images')->find(203);
在 属性 模型中删除此行时:
protected $with = ['images'];
图像模型中的这一行:
protected $with = ['property'];
我希望这个解决方案对你有用。
有一个without()
方法:https://laravel.com/api/5.8/Illuminate/Database/Eloquent/Builder.html#method_without
将 without()
置于关系的双方都有效。
class Property extends EloquentModel {
protected $with = ['images'];
public function images()
{
return $this->hasMany(Image::class)->without('property');
}
}
class Image extends EloquentModel {
protected $with = ['property'];
public function property()
{
return $this->belongsTo(Property::class)->without('images');
}
public function getAlt()
{
return $this->property->title;
}
}
更新:
尽管使用 without()
很容易避免无限循环问题,但通过多年使用 Laravel 的经验,我意识到在模型中设置 $with
是不好的做法,因为它会导致关系总是加载。因此导致循环reference/infinite循环
相反,始终使用with()
明确指定 需要预先加载的必要关系,无论多么深(关系的关系)
例如:
$user = User::with('images' => function ($query) {
$query->with('property' => function ($query) {
$query->with('deeperifneeded' => function ($query) {
//...
});
});
]);
注意:可能需要删除 without()
更新(解决方案)
- 如果您需要
$user->images
中的$image
之一的->user
关系,那么$user
变量已经可用,因为您加载了->images
它! - 不要使用
protected $with
Eloquent 属性。这是一个反模式。 - 而不是明确地从 where/when 按需加载关系是需要的(注意:它不应该阻止你保持干爽!)
- 如果你真的need/want,请看@nicksonyap 的回答。它可以解决问题(我相信——未经测试)。
原创
我 运行 我认为这是一个简单的问题:
- 我有一个
User
对象 有很多Image
s Image
属于User
...(反比关系)
我的问题是我想同时加载 User
模型上的 images()
和 Image
模型上的 user()
。为此,我只是按照文档中的说明设置了 $with
属性。
我的User
模特:
class User extends EloquentModel {
protected $with = ['images'];
public function images()
{
return $this->hasMany(Image::class);
}
}
我的Image
模特:
class Image extends EloquentModel {
protected $with = ['user'];
public function user()
{
return $this->belongsTo(User::class);
}
}
但是表演时:
$user = User::find(203);
这会导致无限循环(php 分段错误)。一定有某种我找不到的循环引用:
[1] 85728 segmentation fault
编辑 2016/02
这是我发现的最简单的"Workaround":
// User.php
public function setRelation($relation, $value)
{
if ($relation === 'images') {
foreach ($value as $image) {
$image->setUser($this);
}
}
return parent::setRelation($relation, $value);
}
当您尝试查找 属性 时,那个 属性 eager 加载它拥有的所有图像,并且每个 Image eager 加载它所属的 属性,即 属性 你试图找到,它将再次开始急切加载它拥有的所有图像。等...
我解决这个问题的方法是不在模型内部进行预加载,而是在调用模型时进行预加载。
所以使用以下内容:
$prop = Property::with('images')->find(203);
在 属性 模型中删除此行时:
protected $with = ['images'];
图像模型中的这一行:
protected $with = ['property'];
我希望这个解决方案对你有用。
有一个without()
方法:https://laravel.com/api/5.8/Illuminate/Database/Eloquent/Builder.html#method_without
将 without()
置于关系的双方都有效。
class Property extends EloquentModel {
protected $with = ['images'];
public function images()
{
return $this->hasMany(Image::class)->without('property');
}
}
class Image extends EloquentModel {
protected $with = ['property'];
public function property()
{
return $this->belongsTo(Property::class)->without('images');
}
public function getAlt()
{
return $this->property->title;
}
}
更新:
尽管使用 without()
很容易避免无限循环问题,但通过多年使用 Laravel 的经验,我意识到在模型中设置 $with
是不好的做法,因为它会导致关系总是加载。因此导致循环reference/infinite循环
相反,始终使用with()
明确指定 需要预先加载的必要关系,无论多么深(关系的关系)
例如:
$user = User::with('images' => function ($query) {
$query->with('property' => function ($query) {
$query->with('deeperifneeded' => function ($query) {
//...
});
});
]);
注意:可能需要删除 without()