Laravel Eloquent:n + 1通过访问者访问相关模型

时间:2014-03-01 10:56:49

标签: php orm laravel eloquent

我在Laravel中抽象模型依赖项时遇到了问题。

我有Metal模型和Fix模型。 A Metal有很多修复,但是当我查询Metal模型时,我需要Metal模型的一个属性,它取决于特定的相关修复。

我使用从金属模型中查询修复模型的访问器来执行此操作。

以下示例:

class Metal extends Eloquent
{
  protected $table = 'metals';

  public function fixes()
  {
    return $this->hasMany('Fix');
  }

  public function getFixAttribute()
  {
    $fix = Fix::where('metal_id', $this->id)
    ->where('currency_id', Session::get('currency'))->remember(10)->first();

    $amFix = $fix->am;

    return $amFix;
  }

  protected $appends = array('fix');
}

如果没有->remember(10),每次需要Metal模型时,我最终都会对金属表中查询的每一行执行db查询。 n+1问题。

示例 - 假设数据库中有10个金属,dd(Metal::all());将查询金属表,然后修复表10次以获取每个金属的修复属性。

此外,我不是每次都需要fixAttribute,但我会经常需要它 - 这就是我附加属性访问器的原因。

解决此问题的最佳方法是什么?任何人都可以指出我正确的方向吗?

理想情况下,我想查询修复表一次为每个金属提供一个修复,然后将metal_id与金属表匹配,并在金属修复访问器中使用它。

1 个答案:

答案 0 :(得分:1)

我认为您可以使用Eager LoadingEager Load Constraints)来使用n+ query problem方法缩小with

$metalsWithFixes = Metal::with(array('fixes' => function($q){
    $q->where('currency_id', Session::get('currency'));
}))->get();

更新:您可以将关系用作$metalsWithFixes->first()->fixes并可以从fix tablw中选择字段,但关系密钥(metal_id)必须存在于选择array

$metalsWithFixes = Metal::with(array('fixes' => function($q){
    $q->where('currency_id', Session::get('currency'))->select(array('metal_id', 'am'));
}))->get();

您可以在loop中使用view (blade)作为:

@foreach($metalsWithFixes as $metal)

    {{ $metal->fieldName }}

    @foreach($metalWithFix->fixes as $fix)
        {{ $fix->am }}
    @endforeach;

@endforeach

由于它是one-to-many关系,因此$metal->fixes将返回多个fix或一个(如果只有一个)但是array