Laravel 4;モデルProject
とPart
があり、ピボットテーブルproject_part
と多対多の関係があります。ピボットテーブルには、プロジェクトで使用されるパーツIDの番号を含む列count
があります。例:
id project_id part_id count
24 6 230 3
ここで、project_id
6は、3個のpart_id
230を使用しています。
1つのパーツが同じプロジェクトに対して複数回リストされる場合があります。例:
id project_id part_id count
24 6 230 3
92 6 230 1
プロジェクトのパーツリストを表示するときに、part_id
を2回表示したくないので、結果をグループ化します。
私のプロジェクトモデルにはこれがあります:
public function parts()
{
return $this->belongsToMany('Part', 'project_part', 'project_id', 'part_id')
->withPivot('count')
->withTimestamps()
->groupBy('pivot_part_id')
}
しかしもちろん、私のcount
値は正しくありません。ここで、私の問題が発生します。プロジェクトのすべてのグループ化された部分の合計を取得するにはどうすればよいですか?
project_id
6のパーツリストは次のようになります。
part_id count
230 4
Projects
-Parts
の関係に入れて、熱心にロードできるようにしたいと思います。
N + 1の問題が発生しない限り、これを行う方法に頭を悩ませることはできません。洞察をいただければ幸いです。
更新:一時的な回避策として、プロジェクトの合計パーツ数を取得するためのプレゼンターメソッドを作成しました。しかし、これは私にN +1の問題を与えています。
public function sumPart($project_id)
{
$parts = DB::table('project_part')
->where('project_id', $project_id)
->where('part_id', $this->id)
->sum('count');
return $parts;
}
コードソース から:
すべてのピボット列に「pivot_」プレフィックスを付けてエイリアスを作成する必要があります。これにより、モデルから簡単に抽出して、モデルに取得してハイドレイトしたときにピボット関係に配置できます。
したがって、select
メソッドでも同じことができます
public function parts()
{
return $this->belongsToMany('Part', 'project_part', 'project_id', 'part_id')
->selectRaw('parts.*, sum(project_part.count) as pivot_count')
->withTimestamps()
->groupBy('project_part.pivot_part_id')
}
Collection
で合計してみてください、
_$project->parts->sum('pivot.count');
_
これが私が見つけた最良の方法です。クリーンで(読みやすく)、parts
多対多の定義で、スコープ、順序付け、および関係属性のキャッシュをすべて再利用できます。
@hebron with('parts')
to eager load を使用する場合、このソリューションのN +1の問題はありません。 _$project->parts
_(withoutfuntion call)はキャッシュされた属性であるため、すべてのデータを含む Collection のインスタンスを返します。また、sum('pivot.count')
はCollection
のメソッドであり、純粋な関数ヘルパーが含まれています(jsの世界では アンダースコア のようにデータベースとは関係ありません)。
完全な例:
関係部分の定義:
_class Project extends Model
{
public function parts()
{
return $this->belongsToMany('Part', 'project_part', 'project_id', 'part_id')
->withPivot('count')
->withTimestamps();
}
}
_
あなたがそれを使うとき(N + 1問題を避けるために熱心な負荷が重要であることに注意してください)、
_App\Project::with('parts')->get()->each(function ($project) {
dump($project->parts->sum('pivot.count'));
});
_
または、Project.phpでsum関数を定義できます。
_class Project extends Model
{
...
/**
* Get parts count.
*
* @return integer
*/
public function partsCount()
{
return $this->parts->sum('pivot.count');
}
}
_
呼び出し側でwith('parts')
を回避したい場合(デフォルトでは熱心なロードパーツ)、_$with
_属性を追加できます
_class Project extends Model
{
/**
* The relations to eager load on every query.
*
* @var array
*/
protected $with = ['parts'];
...
}
_
使用できる最善の方法は次のとおりです。
$project->parts->sum('pivot.count');
私は同じ問題に直面しましたが、これで問題は解決しました。