如何在 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
如果没有为 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.