我已经整天解决了急切的加载/ n + 1问题,研究和阅读并观看了有关此问题的教程,但尚未解决。我已经为模型建立了关系,但是当我使用辅助函数传递数据时,我遇到了这个n + 1问题。 我想从网址site.com/Artist/songs中获取一个艺术家名字并获取所有歌曲并显示这样的网址。
site.com/$Artist/songs/$id
我的artists / index.blade.php视图如下所示http://i61.tinypic.com/2nqzatk.jpg 我不确定我在这里缺少什么。
提前致谢!
我的桌子
歌曲 id,title,body,slug,hits,artist_id,created_at,updated_at
艺术家 id,name,body,created_at,updated_at
routes.php文件
Event::listen('illuminate.query', function($query)
{
var_dump($query);
});
...
Route::get('{artist}/songs', 'ArtistsController@index');
Route::get('{artist}/songs/{id}', ['as' => 'artist.songs.show', 'uses' => 'ArtistsController@show']);
型号:Song.php
class Song extends Eloquent {
protected $guarded = ['id'];
/**
* Setting up relationship for the artist model for easier usage
*
*/
public function artist()
{
return $this->belongsTo('Artist');
}
// Override find method
public static function find($id, $name = null)
{
$song = static::with('artist')->find($id);
// If the song is found
if ($song)
{
// If the song doesn't belong to that artist, throw an exception which will redirect to home, defined in global.php
if ($name and $song->artist->name !== $name)
{
throw new Illuminate\Database\Eloquent\ModelNotFoundException;
}
return $song;
}
// If the song is not found, throw an exception which will redirect to home, defined in global.php
else
{
throw new Illuminate\Database\Eloquent\ModelNotFoundException;
}
}
// Get songs from artist
public static function byArtist($name)
{
return Artist::byName($name)->songs;
}
}
Model Artist.php
class Artist extends Eloquent {
protected $fillable = [];
/**
* Setting up relationship with the song model for easier usage
* $artist->songs;
*/
public function songs()
{
return $this->hasMany('Song');
}
// Get artist by name
public static function byName($name)
{
return static::whereName($name)->first();
}
}
Controller:ArtistsController.php
class ArtistsController extends BaseController {
// Set default layout for this controller
protected $layout = 'layouts.master';
/**
* Display a listing of the resource.
* GET /artists
*
* @return Response
*/
public function index($name)
{
$this->data['songs'] = Song::byArtist($name);
$this->layout->content = View::make('artists.index', $this->data);
}
helpers.php
function link_to_artist_song(Song $song)
{
return link_to_route('artist.songs.show', $song->title, [$song->artist->name, $song->id]);
}
艺术家的索引视图 artists / index.blade.php http://i61.tinypic.com/2nqzatk.jpg
@extends('layouts.master')
@section('content')
@if(isset($songs))
<h1>All Songs</h1>
<ul class="list-group">
@foreach($songs as $song)
<li class="list-group-item">{{ link_to_artist_song($song) }}</li>
@endforeach
</ul>
@endif
@stop
答案 0 :(得分:2)
你从不急于加载任何东西,这就是你面临n + 1问题的原因。 如果我说得对,你在这里使用的代码有点难,你想要所有给定艺术家的歌曲带有来自url的$ name,对吗?
所以,这就是你需要的一切:
// controller
public function index($name)
{
// with('songs') is eager loading related songs for you
$this->data['artist'] = Artist::with('songs')->whereName($name)->first();
$this->layout->content = View::make('artists.index', $this->data);
}
// the problem of your queries is in the helper:
function link_to_artist_song(Song $song)
{
return link_to_route('artist.songs.show', $song->title, [
$song->artist->name, // this is calling db query for each song to retrieve its artist (despite it is always the same)
$song->id]);
}
// so instead use this in your view
@foreach($artist->songs as $song)
<li class="list-group-item">
{{ link_to_route('artist.songs.show', $song->title, [$artist->name, $song->id]) }}
</li>
@endforeach
答案 1 :(得分:0)
当你有很多有很多艺术家的歌曲时,存在n + 1问题。它必须获得所有歌曲(1个查询),然后为每首歌曲获得艺术家(n个查询)。
在这种情况下,您已经知道了这首歌,因此这是一个查询,那么您需要该歌曲的所有艺术家,这只是一个额外的查询。
如果您试图找到某种类型的歌曲,那么n + 1问题才会发挥作用,这可能会返回许多歌曲。然后,对于每首歌曲,您将不得不进行额外的查询以获得该歌曲的艺术家。这将是渴望加载最有用的地方。
$song = Song::find($id);
$artist = $song->artist;
答案 2 :(得分:0)
每次你抓一首歌,并$song->artist
它都会进行查询。
您也可以使用Query scopes。
class Song extends Eloquent {
public function scopeByArtist($query, $name) {
return Artist::whereName($name)->first()->songs(); //->with('artist');
}
}
像这样艺术家已经装好了。
查询:
$songs = Song::byArtist($name)->get();