如何在 Eloquent 中预先加载具有条件的关系?

How to eager load a relation with a condition in Eloquent?

如果没有为 object 本身设置,我有一个可以从 parent 继承的关系。

举个例子,假设我们的活动有场地。

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

如果我只是为一个事件请求活动并与他们一起工作,那很好。但是如果我尝试为活动加载场地,我只会获得直接在 activity 上设置的场地,而不会从 parent.

请求场地
$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

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

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

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

为了做你想做的事,你需要稍微改变一下。首先,您的 Activity 可以与场地直接相关,因此无需任何条件即可设置该关系。接下来,创建一个访问器方法,它将 return 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 相同。那么你就不用担心 activity.

上缺少 venue id