【发布时间】:2015-12-27 00:59:43
【问题描述】:
当我们加载 Laravel Eloquent 模型及其关系时,如下所示:
$user = User::with('Interest')->find(1);
查询MySQL如下:
100 Prepare select * from `users` where `users`.`id` = ? limit 1
100 Execute select * from `users` where `users`.`id` = '1' limit 1
100 Close stmt
100 Prepare select `interest_id`, `user_interests`.`user_id` as `pivot_user_id`, `user_interests`.`interest_id` as `pivot_interest_id` from `interests` inner join `user_interests` on `interests`.`id` = `user_interests`.`interest_id` where `user_interests`.`user_id` in (?)
100 Execute select `interest_id`, `user_interests`.`user_id` as `pivot_user_id`, `user_interests`.`interest_id` as `pivot_interest_id` from `interests` inner join `user_interests` on `interests`.`id` = `user_interests`.`interest_id` where `user_interests`.`user_id` in ('1')
100 Close stmt
100 Quit
在下一行,我想访问已加载的 Interest 模型,在我看来,它已经被 ::with 语句预先加载了。但是,当我尝试像这样访问interest_id 时:
$user->interest->interest_id;
我看到另一个数据库查找出现在 MySQL 查询日志中访问相同的已预加载关系:
100 Prepare select `interest_id`, `user_interests`.`user_id` as `pivot_user_id`, `user_interests`.`interest_id` as `pivot_interest_id` from `interests` inner join `user_interests` on `interests`.`id` = `user_interests`.`interest_id` where `user_interests`.`user_id` = ?
100 Execute select `interest_id`, `user_interests`.`user_id` as `pivot_user_id`, `user_interests`.`interest_id` as `pivot_interest_id` from `interests` inner join `user_interests` on `interests`.`id` = `user_interests`.`interest_id` where `user_interests`.`user_id` = '1'
100 Close stmt
100 Quit
我希望 Laravel 为我提供已经加载的关系,但它却再次查询 MySQL。我看到当我使用getRelation('Interest') 时,它确实返回了已经在User::with('Interest') 上加载的关系并且不再查询MySQL,如下所示:
$user->getRelation("Interest")->interest_id;
我想知道这是否是要走的路,如果我对使用 ::with 进行急切加载的期望完全错误?或者也许还有其他最佳实践来访问预加载的关系而不是再次查询 MySQL。在我看来,多次查询数据库以获取相同的信息更昂贵。
用户模型
<?php namespace App\Models;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use App\Models;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
protected $table = 'users';
protected $fillable = ['name', 'email', 'password'];
protected $hidden = ['password', 'remember_token', 'created_at', 'updated_at'];
public function Interest()
{
return $this->belongsToMany('App\Models\Interest', 'user_interests', 'user_id', 'interest_id')->select(array('interest_id'));
}
}
兴趣模型
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Interest extends Model
{
protected $table = 'interests';
protected $fillable = ['description', 'parent_id'];
protected $hidden = ['created_at', 'updated_at'];
}
【问题讨论】:
-
这种行为不正常。请在您定义关系的位置提供您的模型代码。为什么你渴望加载时使用“兴趣”,而访问时使用“兴趣”?
-
@JaviStolz,您的评论让我注意到了“资本”问题。我已将 User 模型中的函数声明更改为小写复数,如下所示:
public function interests() { ... }以及它被调用的地方,现在一切都按预期工作。奇怪的是它也适用于资本问题并且没有抛出异常。 -
尝试添加反向关系。也尝试删除
->select(array('interest_id'))