Eager load hasMany & belongsTo (circular reference/infinite loop)

北慕城南 提交于 2019-12-12 20:49:41

问题


UPDATE (SOLUTION)

  • If you need ->user relationship from one of the $image inside $user->images, then $user variable is already available cause you loaded the ->images from it!
  • Don't use protected $with Eloquent property. It's an anti-pattern.
  • Instead explicitly eager load relationships on-demand from where/when it's needed (Note: it should not prevent you to keep things DRY!)
  • If you really need/want to, see @nicksonyap answer. It does the trick (I believe – not tested).

ORIGINAL

I'm running into what I believe is a simple problem:

  • I have a User object that has many Images
  • Image belongs to User... (inverse relation)

My problem is that I want to eager load both the images() on the User model and the user() on the Image model. To do so, I just setup a $with property as explained in the docs.

My User model:

class User extends EloquentModel {
    protected $with = ['images'];

    public function images()
    {
        return $this->hasMany(Image::class);
    }
}

My Image model:

class Image extends EloquentModel {
    protected $with = ['user'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

But when performing:

$user = User::find(203);

This results in an infinite loop (php segmentation fault). There must be some kind of circular reference that I am not able to locate:

[1]    85728 segmentation fault

EDIT 2016/02

This is the simplest "Workaround" I found:

// User.php
public function setRelation($relation, $value)
{
    if ($relation === 'images') {
        foreach ($value as $image) {
            $image->setUser($this);
        }
    }
    return parent::setRelation($relation, $value);
}

回答1:


There is a without() method: https://laravel.com/api/5.8/Illuminate/Database/Eloquent/Builder.html#method_without

Placing without() on both sides of a relationship worked.

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



回答2:


When you try to find a Property, that property eager loads all the images it has and every Image eager loads the property it belongs to, which is the property you try to find, which will again start to eager load all the images it has. etc...

The way I would resolve this problem is by not eager loading inside the models, but by eager loading when calling the models.

so using the following:

$prop = Property::with('images')->find(203);

while removing this line in the Property model:

protected $with = ['images'];

And this line in the Image model:

protected $with = ['property'];

I hope this solution works for you.



来源:https://stackoverflow.com/questions/34995187/eager-load-hasmany-belongsto-circular-reference-infinite-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!