我正试图弄清楚如何形成我的数据库查询来建立一个项目集合,每个项目都有一组人员,以及他们提交的分配的工作时间和每日轮班时间。
在我目前所拥有的代码中,我选择了当月正在运行的项目。对于其中的每个项目,我选择了当月正在处理该项目的人员。然后,对于每个人员,我又进行了两次查询,以获取他们的分配日期和提交的轮班详细信息。
这确实有效,并且创建了我想要的数据结构,但是由于需要进行大量的单独数据库查询,所以速度很慢。
一定有一种更有效的方法通过子查询或其他方式来完成这件事?
$projects = Project::select([
'projects.id',
'projects.name',
'projects.start',
'projects.finish'
])
->where('projects.start', '<=', Carbon::now()->endOfMonth())
->where('projects.finish', '>=', Carbon::now()->startOfMonth())
->get();
foreach($projects as $project)
{
$project->personnel = ProjectUser::select([
'project_users.id',
'project_users.user_id',
'users.name',
'project_users.role'
])
->join('users', 'users.id', '=', 'project_users.user_id')
->join('assignments', 'assignments.project_user_id', '=', 'project_users.id')
->where('project_users.project_id', $project->id)
->where('assignments.start', '<=', Carbon::now()->endOfMonth())
->where('assignments.finish', '>=', Carbon::now()->startOfMonth())
->distinct('users.name')
->get();
foreach($project->personnel as $person)
{
$person->assignments = Assignment::select([
'assignments.start',
'assignments.finish',
'assignments.travel_out',
'assignments.travel_home'
])
->where('assignments.project_user_id', $person->project_user_id)
->get();
$person->shifts = WorkShift::select([
'work_shifts.id',
'work_shifts.role',
'work_shifts.date',
'work_shifts.start',
'work_shifts.hours',
'work_shifts.status',
'work_shifts.remarks'
])
->where('work_shifts.user_id', $person->user_id)
->where('work_shifts.project_id', $project->id)
->get();
}
}
更新
我现在主要是通过使用模型关系来实现这一点。我的最后一个问题是,我可以在控制器的顶层过滤日期范围内的项目,但我还需要将该过滤器应用于分配和work_shift。
因此,我只想检索在请求的日期范围内具有分配的project_users,然后只挑选出匹配的分配和work_shift。
我目前掌握的是...
// Controller
public function load(Request $request)
{
$projects = Project::select([
Project::ID,
Project::NAME,
Project::START,
Project::FINISH
])
// Only able to filter by date range here?!?
->where(Project::START, '<=', Carbon::now()->endOfYear())
->where(Project::FINISH, '>=', Carbon::now()->startOfYear())
->with('project_staff')
->orderBy(Project::START)
->get();
return response()->json([
'projects' => $projects
]);
}
// Project Model
// Just want to get the staff that are assigned to the project
// between the selected date range
public function project_staff()
{
return $this->hasMany(ProjectUser::class)
->select([
ProjectUser::ID,
ProjectUser::PROJECT_ID,
ProjectUser::USER_ID,
User::NAME,
ProjectUser::ROLE
])
->whereIn(ProjectUser::STATUS, [
ProjectUser::STATUS_RESERVED,
ProjectUser::STATUS_ASSIGNED,
ProjectUser::STATUS_ACCEPTED
])
->join(User::TABLE, User::ID, '=', ProjectUser::USER_ID)
->with([
'assignments',
'shifts'
]);
}
// Assignments Model
// Again, just want the assignments and workshifts that fall
// within the selected date range
public function assignments()
{
return $this->hasMany(Assignment::class, 'projectUser_id')
->select([
Assignment::PROJECT_USER_ID,
Assignment::START,
Assignment::FINISH,
Assignment::TRAVEL_OUT,
Assignment::TRAVEL_HOME
]);
}
public function shifts()
{
return $this->hasMany(WorkShift::class, ['project_id','user_id'], ['project_id','user_id'])
->select([
WorkShift::ID,
WorkShift::USER_ID,
WorkShift::PROJECT_ID,
WorkShift::ROLE,
WorkShift::DATE,
WorkShift::START,
WorkShift::HOURS,
WorkShift::STATUS,
WorkShift::REMARKS
]);
}
// WorkShift Model
public function projectUser()
{
return $this->belongsTo(ProjectUser::class, ['project_id','user_id'], ['project_id','user_id']);
}
2条答案
按热度按时间yhuiod9q1#
经过一天的学习,我找到的解决方案是在模型之间建立非常简单的关系,并在使用 * with *()调用关系查询时,在附加到关系查询的过滤器函数中实现所有额外的查询逻辑。
请参见www.example.comhttps://laravel.com/docs/8.x/eloquent-relationships#constraining-eager-loads
我的代码现在工作效率高得多,在dev-env中,在大约10 - 20ms内只对数据库进行4次调用,并以正确的形式构造结果数据,以便将整个集合作为JSON响应返回。
非常感谢任何花时间和思想来帮助我解决这个问题的人。非常感谢你的努力。
plicqrtu2#
如前所述,您可以使用Laravel内置的关系,或者,您可以构造一个巨大的查询并将所有数据连接在一起;
就像这样: