【问题标题】:How to eager load a relation with a condition in Eloquent?如何在 Eloquent 中急切地加载与条件的关系?
【发布时间】:2018-01-14 02:26:04
【问题描述】:

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

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

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

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

【问题讨论】:

标签: laravel eloquent eager-loading


【解决方案1】:

就其本质而言,预先加载的关系不会为每个父模型运行关系方法。如果他们这样做了,您将遇到 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;
    }
}

另一个选项是始终在Activity 上分配venue_id,即使它与Event venue_id 相同。那么你就不用担心活动中缺少场地id了。

【讨论】:

  • 这个我没试过,但是$this->venue不会打电话给getActivityVenueAttribute()吗?无论如何,我喜欢你的想法,这正是我所需要的。如果发生冲突,我总是可以将 venue() 重命名为 venueRelation() 或类似名称。
  • 没关系,我注意到您将属性称为activityVenue 而不仅仅是venue
  • @Džuris 是的,我的意思是在我的回答中提到这一点,但忘记了。我专门命名了访问器属性与关系名称不同,这样它就不会与尝试访问关系属性发生冲突。希望对您有所帮助。
猜你喜欢
  • 1970-01-01
  • 2017-09-30
  • 2019-01-22
  • 2019-07-08
  • 1970-01-01
  • 2019-09-08
  • 2015-03-12
  • 2019-09-14
  • 2021-04-28
相关资源
最近更新 更多