没有主键但在多个重叠字段上加载模型一对多关系 eloquent 方式
Load model one to many relation eloquent way without primary key but on multiple overlapping fields
我正在处理一个较旧的项目,我的任务是在我们进行完全重写的同时加快某些部分的速度,因为代码维护不善,编写不当且已过时去做。
我无意中遇到了项目核心的问题,因此我无法在不破坏几乎所有其他内容的情况下更改它。所以我需要以 eloquent 方式加载“关系”(使用 Planning:with('availability')
但没有真正的外国 ID,它包含多个字段。
有没有一种方法可以在具有重叠字段的一个查询中加载所有内容,而不是单独加载,从而造成 n+1 问题?
+--------------+-----------------+
| Planning | Availability |
+--------------+-----------------+
| planning_id | availability_id |
| date | date |
| startHour | startHour |
| stopHour | stopHour |
| candidate_id | candidate_id |
| section_id | section_id |
+--------------+-----------------+
从上面的例子中你可以看到重叠的字段是 date, startHour, stopHour, candidate_id and section_id.
我尝试了 get...attribute 但它仍然加载了 n+1,我尝试将它包含在 ->with(['availabilities'])
中但是这不起作用,因为我要求
模型而不是关系:
为更清晰起见进行编辑:
规划模型:
public function availabilities()
{
return Availability::where('section_id', $this->section_id)
->where('candidate_id', $this->candidate_id)
->where('planningDate', $this->planningDate)
->where('startHour', $this->startHour)
->where('stopHour', $this->stopHour)
->get();
}
public function availabilities2()
{
return $this->hasMany('App\Models\Availability', 'candidate_id', 'candidate_id')
}
控制器:
$plannings = Planning::with(['availabilities'])->get();
$plannings = Planning::with(['availabilities2' => function ($query) {
// $this is suppose to be Planning model but doesn't work
$query->where('section_id', $this->section_id)
->where('planningDate', $this->planningDate)
->where('startHour', $this->startHour)
->where('stopHour', $this->stopHour);
// ---- OR ---- //
// Don't have access to planning table here
$query->where('section_id', 'planning.section_id')
->where('planningDate', 'planning.planningDate')
->where('startHour', 'planning.startHour')
->where('stopHour', 'planning.stopHour');
}])->get();
当你想在 where()
方法中使用多个字段时,你最常在 where()
方法中插入一个数组:
This document can help you
- 将您的代码更改为:
return Availability::where([
['section_id', $this->section_id],
['candidate_id', $this->candidate_id],
['planningDate', $this->planningDate],
['startHour', $this->startHour],
['stopHour', $this->stopHour]
])->firstOrFail();
首先,为了能够加载我的关系,我选择了匹配的键之一,并选择了匹配最少的键,在我的例子中是 section_id
.
所以在我的 Planning 模型上我有一个函数:
public function availabilities()
{
return $this->hasMany('App\Models\Availability', 'section_id', 'section_id');
}
这样我就可以在需要时加载数据:Planning:with('availability')
。
然而,由于我有一些其他键需要匹配,所以我找到了一种通过向其添加子查询来限制这种关系的方法:
$planning = Planning::with([
'availabilities' => function ($query) {
$query->where('candidate_id', $this->candidate_id)
->where('startHour', $this->startHour)
->where('stopHour', $this->stopHour);
},
// Any other relations could be added here
])
->get();
这不是最好的方法,但这是我发现它不会获得太多额外数据的唯一方法,同时也尊重我的关系
我正在处理一个较旧的项目,我的任务是在我们进行完全重写的同时加快某些部分的速度,因为代码维护不善,编写不当且已过时去做。
我无意中遇到了项目核心的问题,因此我无法在不破坏几乎所有其他内容的情况下更改它。所以我需要以 eloquent 方式加载“关系”(使用 Planning:with('availability')
但没有真正的外国 ID,它包含多个字段。
有没有一种方法可以在具有重叠字段的一个查询中加载所有内容,而不是单独加载,从而造成 n+1 问题?
+--------------+-----------------+
| Planning | Availability |
+--------------+-----------------+
| planning_id | availability_id |
| date | date |
| startHour | startHour |
| stopHour | stopHour |
| candidate_id | candidate_id |
| section_id | section_id |
+--------------+-----------------+
从上面的例子中你可以看到重叠的字段是 date, startHour, stopHour, candidate_id and section_id.
我尝试了 get...attribute 但它仍然加载了 n+1,我尝试将它包含在 ->with(['availabilities'])
中但是这不起作用,因为我要求
模型而不是关系:
为更清晰起见进行编辑:
规划模型:
public function availabilities()
{
return Availability::where('section_id', $this->section_id)
->where('candidate_id', $this->candidate_id)
->where('planningDate', $this->planningDate)
->where('startHour', $this->startHour)
->where('stopHour', $this->stopHour)
->get();
}
public function availabilities2()
{
return $this->hasMany('App\Models\Availability', 'candidate_id', 'candidate_id')
}
控制器:
$plannings = Planning::with(['availabilities'])->get();
$plannings = Planning::with(['availabilities2' => function ($query) {
// $this is suppose to be Planning model but doesn't work
$query->where('section_id', $this->section_id)
->where('planningDate', $this->planningDate)
->where('startHour', $this->startHour)
->where('stopHour', $this->stopHour);
// ---- OR ---- //
// Don't have access to planning table here
$query->where('section_id', 'planning.section_id')
->where('planningDate', 'planning.planningDate')
->where('startHour', 'planning.startHour')
->where('stopHour', 'planning.stopHour');
}])->get();
当你想在 where()
方法中使用多个字段时,你最常在 where()
方法中插入一个数组:
This document can help you
- 将您的代码更改为:
return Availability::where([
['section_id', $this->section_id],
['candidate_id', $this->candidate_id],
['planningDate', $this->planningDate],
['startHour', $this->startHour],
['stopHour', $this->stopHour]
])->firstOrFail();
首先,为了能够加载我的关系,我选择了匹配的键之一,并选择了匹配最少的键,在我的例子中是 section_id
.
所以在我的 Planning 模型上我有一个函数:
public function availabilities()
{
return $this->hasMany('App\Models\Availability', 'section_id', 'section_id');
}
这样我就可以在需要时加载数据:Planning:with('availability')
。
然而,由于我有一些其他键需要匹配,所以我找到了一种通过向其添加子查询来限制这种关系的方法:
$planning = Planning::with([
'availabilities' => function ($query) {
$query->where('candidate_id', $this->candidate_id)
->where('startHour', $this->startHour)
->where('stopHour', $this->stopHour);
},
// Any other relations could be added here
])
->get();
这不是最好的方法,但这是我发现它不会获得太多额外数据的唯一方法,同时也尊重我的关系