一对多关系计数 - 访问关系的差异

时间:2014-11-10 13:33:37

标签: laravel laravel-4 orm eloquent relationship

我有一对多的关系 - Entry可以有很多Visits

在我的Entry模型中,我有以下方法:

public function visits() {
    return $this->hasMany ('Visit', 'entry_id','id');
}

public function visitsCount() {
    return $this->hasMany('Visit', 'entry_id','id')
        ->selectRaw('SUM(number) as count')
        ->groupBy('entry_id');
}

在Blade中,我可以使用以下方式获得参赛作品的访问次数:

{{$entry->visits()->count() }}

{{ $entry->visitsCount()->first()->count }}

如果我想创建访问者以获取访问次数,我可以定义:

public function getNrVisitsAttribute() 
{
    $related = $this->visitsCount()->first();
    return ($related) ? $related->count : 0;
}

现在我可以使用:

{{ $entry->nr_visits }}

问题

  1. 在某些例子中,我看到以这种方式定义这种关系:

    public function getNrVisitsAttribute()
    {    
        if (!array_key_exists('visitsCount', $this->relations)) {
            $this->load('visitsCount');
        }
        $related = $this->getRelation('visitsCount')->first();
        return ($related) ? $related->count : 0;
    }
    

    问题是:这与简单方法之间的区别是什么?#34;我一开始就表现出来了?是更快/使用更少的资源还是......?

  2. 为什么这种方法在这种情况下不起作用? $relatednull,因此访问者返回0,而使用"简单方法"它会返回正确的访问次数

  3. 我还尝试将visitsCount方法关系从hasMany更改为hasOne,但它并没有改变任何内容。

2 个答案:

答案 0 :(得分:1)

1你的关系不起作用,因为你没有select外键:

public function visitsCount() {
    // also use hasOne here
    return $this->hasOne('Visit', 'entry_id','id')
        ->selectRaw('entry_id, SUM(number) as count')
        ->groupBy('entry_id');
}

2你的访问者应该与关系具有相同的名称才能有意义(这就是为什么我首先创建这些访问者):

public function getVisitsCountAttribute() 
{
   if ( ! array_key_exists('visitsCount', $this->relations)) $this->load('visitsCount');

   $related = $this->getRelation('visitsCount');

   return ($related) ? $related->count : 0;
}

这个访问器只是一种以这种方式调用计数的方便方法:

$entry->visitsCount;

而不是

$entry->visitsCount->count;
// or in your case with hasMany
$entry->visitsCount->first()->count;

所以它与性能无关。

还要注意,它不是以不同方式定义关系,它需要像上面那样定义关系。

答案 1 :(得分:0)

假设您的架构反映了visits表中每次访问的一个记录/模型,最好的方法是摆脱visitsCount()关系并仅使用$entry->visits->count()来检索数字访问该条目。

这样做的原因是,一旦加载了这个关系,它就会简单地计算集合中的模型而不是重新查询它们(如果使用单独的关系)

如果您的担忧是开销和不必要的查询:我的建议是将这些模型作为用户对象的子项在基本控制器中急切加载并缓存它,因此您唯一需要重新查询任何模型它是在有变化的时候。

<强> BaseController:

public function __construct(){

    if(!Cache::has('user-'.Auth::user()->id)){
        $this->user = User::with('entries.visits')->find(Auth::user()->id);
        Cache::put('user-'.Auth::user()->id, $this->user, 60);
    } else {
        $this->user = Cache::get('user-'.Auth::user()->id);
    }

}

然后在Entry模型上设置一个观察者,以便在保存时刷新用户缓存。如果您使用MemcachedReddis,另一种可能是使用缓存标记,这样您就不必每次Entry模型都清空整个用户的缓存添加或修改。

当然,这也假定每个Entry与用户相关,但是,如果它不是,并且您需要单独使用Entry作为父级,则相同的逻辑可以通过移动Cache

中的EntryController课程来应用