如何基于自身年份条件预加载EmployeeAchievement关联的PositionAllowance
问题
现有以下5个模型:
YearPositionPositionAllowance:Position与Year的中间表,新增allowance字段,用于定义指定年份下各职位的津贴金额。EmployeeEmployeeAchievement:记录员工绩效,存储员工当前职位及对应年份信息。
需求:获取EmployeeAchievement记录时,如何根据其自身的年份,预加载对应的唯一PositionAllowance?优先使用Eloquent实现,也接受其他方案。
数据示例
> Year >> id: 1 , year: 2023 >> id: 2 , year: 2024 > Position >> id: 1 , name: Junior >> id: 2 , name: Senior > PositionAllowance >> id: 1 , position_id: 1 , year_id: 1 , allowance: 100 // 2023年,Junior职位津贴100美元 >> id: 2 , position_id: 1 , year_id: 2 , allowance: 200 // 2024年,Junior职位津贴200美元 > Employee >> id: 1 , name: Joe , position_id: 1 > EmployeeAchievement >> id: 1 , employee_id: 1 , current_position_id: 1 , year_id: 1 // 2023年Joe应得100美元津贴 >> id: 2 , employee_id: 1 , current_position_id: 1 , year_id: 2 // 2024年Joe应得200美元津贴
期望结果
EmployeeAchievement[0] => id: 1 employee => id: 1 , name: Joe .... positionAllowance => id: 1 , allowance: 100 EmployeeAchievement[1] => id: 2 employee => id: 1 , name: Joe .... positionAllowance => id: 2 , allowance: 200
解决方案
方法一:Eloquent关联实现(推荐)
在EmployeeAchievement模型中定义关联方法,通过自身的current_position_id和year_id匹配对应的PositionAllowance:
// app/Models/EmployeeAchievement.php namespace App\Models; use Illuminate\Database\Eloquent\Model; class EmployeeAchievement extends Model { // 关联员工模型 public function employee() { return $this->belongsTo(Employee::class); } // 关联对应年份和职位的津贴 public function positionAllowance() { return $this->hasOne(PositionAllowance::class) ->whereColumn('position_id', 'current_position_id') ->whereColumn('year_id', 'year_id'); } }
查询时直接预加载关联关系,就能得到包含对应津贴的结果:
$achievements = EmployeeAchievement::with(['employee', 'positionAllowance'])->get();
方法二:查询构造器手动关联
如果不需要定义模型关联,也可以通过JOIN查询直接整合数据:
$achievements = EmployeeAchievement::select( 'employee_achievements.*', 'position_allowances.id as allowance_id', 'position_allowances.allowance' ) ->leftJoin('position_allowances', function ($join) { $join->on('position_allowances.position_id', '=', 'employee_achievements.current_position_id') ->on('position_allowances.year_id', '=', 'employee_achievements.year_id'); }) ->with('employee') ->get();
这种方式会把津贴字段直接附加到EmployeeAchievement实例中,同样能满足需求。
注意事项
- 确保
PositionAllowance表中position_id和year_id的组合是唯一约束,避免出现多条匹配结果导致关联异常。 - 如果需要处理无对应津贴的场景,使用
leftJoin(对应Eloquent的hasOne默认是内联,若要左联可改为hasOne(...)->withDefault())。
内容的提问来源于stack exchange,提问作者rifqy abdl
相关产品推荐
相关产品推荐

