2015-02-11 38 views
5

http://laravel.com/docs/4.2/eloquent#dynamic-properties多次调用Eloquent动态属性是否会多次访问数据库?

class Phone extends Eloquent { 

    public function user() 
    { 
     return $this->belongsTo('User'); 
    } 

} 

$phone = Phone::find(1); 

现在,如果我那么做这样的事情:

echo $phone->user->email; 
echo $phone->user->name; 
echo $phone->user->nickname; 

威尔洋洋洒洒做一个数据库调用的每一次我使用->user动态属性?或者这足够聪明,可以在第一次通话时缓存用户?

+0

一次迭代将对'Phone'和'User'通话。多次迭代你必须急切加载。 http://laravel.com/docs/5.0/eloquent#eager-loading – user2094178 2015-02-11 04:23:48

+0

http://laravel.com/docs/4.2/eloquent#eager-loading – user2094178 2015-02-11 04:24:35

+3

我相信对'$ phone-> user'的第一个引用将加载具有该模型本地所有属性的“用户”模型。假定'email','name'和'nickname'存储在'User'中,那么这将导致只有两个数据库查询(一个用于电话,另一个用于用户)。试试看:在这些语句之后,运行dd(\ DB :: getQueryLog())来查看所做的确切查询。 – bishop 2015-02-11 04:27:26

回答

5

在您的示例中,$phone对象上的user属性将被延迟加载,但只会加载一次。

请记住,一旦加载对象,它不会反映对基础表的任何更改,除非使用load方法手动重新加载关系。

下面的代码说明的例子:

$phone = Phone::find(1); 

// first use of user attribute triggers lazy load 
echo $phone->user->email; 

// get that user outta here. 
User::destroy($phone->user->id); 

// echoes the name just fine, even though the record doesn't exist anymore 
echo $phone->user->name; 

// manually reload the relationship 
$phone->load('user'); 

// now will show null, since the user was deleted and the relationship was reloaded 
var_export($phone->user); 
+0

这意味着,即使我使用预先加载来获取相同的数据,当我仅获取一个对象时仍然会得到两个数据库调用。完美总结我对此的疑问。谢谢。 – thomthom 2015-02-11 05:17:13

+2

@thomthom是的,急切的加载将创建至少两个数据库调用。但是,它可以防止n + 1问题。如果您执行了'$ phones = Phone :: all();',然后遍历所有电话对象并显示用户名,则会执行一个查询来获取所有电话,然后为每个单独的用户查询循环迭代(n + 1)。但是,如果您通过执行'$ phones = Phone :: with('user') - > get();'来执行加载操作,并且运行相同的foreach,则只会完成2个数据库调用,一个用于电话,一个用于所有相关用户。 – patricus 2015-02-11 05:21:53

相关问题