如何在Eloquent中急切加载与条件的关系?

时间:2018-01-14 02:26:04

标签: laravel eloquent eager-loading

如果没有为对象本身设置,我有一个可以从父级继承的关系。

对于示例设置,假设我们有具有场地的事件。

class Event extends Model
{
    public function venue()
    {
        return $this->belongsTo('App\Venue');
    }

    public function activities()
    {
        return $this->hasMany('App\Activity');
    }
}

活动中的活动主要发生在同一地点,但有时可能在其他地方,同时仍然属于同一事件。

class Activity extends Model
{
    public function event()
    {
        return $this->belongsTo('App\Event');
    }

    public function venue()
    {
        if ($this->venue_id)
            return $this->belongsTo('App\Venue');

        return $this->event->venue();
    }
}

如果我只是为活动请求活动并与他们一起工作,那很好。但是,如果我试图加载场地进行活动,我只会获得直接在活动中设置的场景,而不是从父级请求场景。

$activities = $event->activities;
$activities->load('venue');  // Works correctly without this line

foreach ($activities as $activity)
    if ($activity->venue)    // Doesn't take venue from the parent (event)
        echo $activity->venue->name;  //Only shows if venue_id is set on activity

有没有机会修复关系,以便我可以批量加载它们?

1 个答案:

答案 0 :(得分:0)

就其本质而言,急切加载的关系没有为每个父模型运行关系方法。如果他们这样做了,你就会遇到N + 1问题,这正是急切加载意味着要解决的问题。

关系方法在用于启动查询的模型上运行一次。这将使基本查询运行,然后将所有父模型ID注入到该查询中。

为了做你想做的事,你需要稍微改变一下。首先,您的Activity可以与场地直接相关,因此无任何条件地设置该关系。接下来,创建一个访问者方法,该方法将返回Activity的正确位置。

因此,您的代码看起来像:

class Activity extends Model
{
    public function event()
    {
        return $this->belongsTo('App\Event');
    }

    public function venue()
    {
        return $this->belongsTo('App\Venue');
    }

    public function getActivityVenueAttribute()
    {
        return $this->venue ?? $this->event->venue ?? null;
    }
}

另一种选择是始终在venue_id上分配Activity,即使它与Event venue_id相同。然后您不必担心活动中缺少场地ID。