Laravel 急切负载约束问题

Posted

技术标签:

【中文标题】Laravel 急切负载约束问题【英文标题】:Laravel Eager Load Constraint issue 【发布时间】:2020-02-26 03:24:20 【问题描述】:

编辑:为清楚起见,这是 Laravel 5.8。

这是针对我正在开发的 HR 应用程序。

他们要求报告显示迟到的人。当然,我想没问题。

所以我有一个表单,其中包含一些用户可以输入的自定义参数、start_date、end_date、工资和一系列部门。

public function show()

    request()->validate([
        'start_date' => 'required|date|before_or_equal:today'
    ]);

    $start = Carbon::parse(request('start_date'));
    $end = request('end_date') ? Carbon::parse(request('end_date')) : today();
    $wage = request('wage');
    $departments = request('departments');

    $query = EmployeePunch::with([
        'employee' => function($query) use ($wage, $departments) 
            // IF I UN COMMENT THESE, IN THE FILTER BLOCK BELOW, THE EMPLOYEE BECOMES UNDEFINED.
            // if($wage != null) 
            //     $query->where('hourly', $wage);
            // 

            // if($departments) 
            //     $query->whereIn('department_id', $departments);
            // 
        ,
        'employee.group',
        'employee.department'
    ])
    ->whereBetween('punch_time', [$start->startOfDay(), $end->endOfDay()])
    // only care about punch in for the day
    ->where('type', 1);

    $results = $query->get();

    $latePunches = $results->filter(function ($i) 
        $day = strtolower($i->punch_time->format('D'));
        $startTime = Carbon::parse(sprintf('%s %s', 
                                            $i->punch_time->format('d-m-Y'), 
                                            $i->employee->group[$day.'_start_time'])
                    );

        return $i->punch_time->isAfter($startTime) 
                && $i->punch_time->diffInMinutes($startTime) >= 5;
    );

    return view('hr.employeeLateReport.show', compact('latePunches'));

所以,我的问题在于我的急切加载,我无法解决这个问题。如果我取消注释快速加载员工中的过滤器,在靠近代码块末尾的过滤器块中,$i->employee 将变为未定义。如果省略过滤器,一切正常。我检查了正在生成的查询,一切看起来都很棒。

任何帮助将不胜感激。

这是关系方法

Employee.php

public function punches()

    return $this->hasMany(EmployeePunch::class);


public function group()

    return $this->belongsTo(Group::class);


public function department()

    return $this->belongsTo(Department::class)->withDefault();

EmployeePunch.php

public function employee()

    return $this->belongsTo(Employee::class);

SQL 输出

【问题讨论】:

您是否检查了这些查询的数据是否存在? 是的。我通过 laravel 调试栏找到了每个查询,并直接在数据库中运行它们,它们都按预期工作。 取消注释内部查询,然后尝试使用whereHas('employee', function($q) ); 和内部whereHas 过滤器使用whereBetween 当您在employee.groupemployee.department 中获取其他嵌套关系时会发生什么?在employee 闭包中尝试$query->with('group')->with('department') @FarrukhAyyaz 你能发表一个答案吗?您的评论使我得到了工作结果。谢谢。 【参考方案1】:

尝试使用whereHas并嵌套whereBetween

$query = EmployeePunch::with([
    'employee' => function($query) use ($wage, $departments) 
        if($wage != null) 
            $query->where('hourly', $wage);
        

        if($departments) 
            $query->whereIn('department_id', $departments);
        
    ,
    'employee.group',
    'employee.department'
])->whereHas('employee', function($q) use($start, $end) 
    $q->whereBetween('punch_time', [$start->startOfDay(), $end->endOfDay()]);
)->where('type', 1);

【讨论】:

那么如果punch_time是一个员工字段,那么$i->punch_time是如何工作的呢? 我们已经检查过,如果我们有关系 employee 那么我们可以处理员工属性 所以你是说,如果我们定义了一个关系,我们可以调用关系的字段,比如$model->relationships_field? punch_time 是一个 EmployeePunch 字段。 EmployteePunch 具有 employee 关系。如果您预先加载或延迟加载关系,您可以访问相关模型。

以上是关于Laravel 急切负载约束问题的主要内容,如果未能解决你的问题,请参考以下文章

约束急切负载的自定义 orderBy()?

带有约束的 Laravel 嵌套急切加载

Laravel 约束急切加载 - 如果关系列应用限制!= 1

如何在 Laravel 中为 ORM 急切加载添加多个键约束?

Laravel 负载与模型条件的关系

急切负载约束和 whereHas