【问题标题】:Load model one to many relation eloquent way without primary key but on multiple overlapping fields在没有主键但在多个重叠字段上加载模型一对多关系的雄辩方式
【发布时间】:2021-10-24 10:07:04
【问题描述】:

我正在处理一个较旧的项目,我的任务是在我们进行完全重写的同时加快某些部分的速度,因为代码维护得很差,写得不好,而且对于它应该做的事情来说已经过时了.

我偶然发现了一个项目核心问题,因此我无法在不破坏几乎所有其他内容的情况下更改它。所以我需要以雄辩的方式加载“关系”(使用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 和 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();

【问题讨论】:

    标签: laravel-5 eloquent


    【解决方案1】:

    首先,为了能够加载我的关系,我选取了一个匹配的键,并选取了匹配最少的一个,在我的例子中是 section_id

    所以在我的规划模型上我有一个函数:

    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();
    

    这不是最好的方法,但这是我发现它不会获得太多额外数据的唯一方法,同时也尊重我的关系

    【讨论】:

      【解决方案2】:

      当您想在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();
      

      【讨论】:

      • 这不是我的意思,它应该被称为我的计划模型中的一个关系,但为了更清楚,我会编辑我的问题
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-27
      • 2016-11-26
      • 2015-06-27
      • 2017-10-16
      • 2014-05-23
      • 2012-10-08
      • 2020-04-10
      相关资源
      最近更新 更多