我有一个名为PRODUCT的模型,它与模型REVIEW有一对多的关系。 REVIEW表有一个'rate'列,我希望在检索所有产品时,REVIEW表中的平均费率与PRODUCT数据相关联。我尝试在PRODUCT模型中创建一个方法,在::with()
命令中调用'rate'来执行此操作,这就是代码:
class Product extends Model{
public function rate(){
return $this->hasMany('App\Review')->select('rate')->avg('rate');
}
在控制器中:
return Product::with('rate')->get();
但我最终会遇到错误..
那么有可能在模型中做到这一点还是有其他方式?任何帮助表示赞赏。
最好保持定义关系的方法尽可能简单。
public function reviews(){
return $this->hasMany('App\Review');
}
现在您可以使用此关系来获取费率。你可以用不同的方式做到:
1.将其添加为appended property:
您可以添加模型中不是列的属性作为附加属性。
protected $appends = ['rate'];
然后有一个函数来赋值:
public functions getRateAttribute(){
return $this->reviews->avg('rate') ?? 0;
}
这个问题是,顾名思义的附加属性总是附加到模型的实例。
所以,如果你只是做以下事情:
$product = Product::first();
即使你不需要费率,laravel仍然会为你准备$product->rate
,因此它将进行平均查询。
2.将它作为一种方法:
当您可以将其创建为方法时,这是一个选项:
public functions getRate(){
return $this->reviews->avg('rate') ?? 0;
}
这样做的好处是,您可以在需要时使用它。这节省了许多不必要的查询,即使您不需要它也会附加属性函数。
然后可以使用它:
$product = Product::first();
// The query fo average will be done below only when you call `getRate` on `$product`
$rate = $product->getRate();
如果我有选择的话,我会选择2作为选项。
还有一个关于Laravel的avg('column_name)
:
null
0.0
的值3.9265
格式给出有效值所以你可以相应地使用你的功能。
你可以尝试这样的事情:
class Product extends Model{
public function review(){
return $this->hasMany('App\Review');
}
public function rate(){
return $this->review()->avg('rate'); // chain your query here
}
}
然后你可以访问它像:
$product = Product::find(1);
dd($product->rate()->get());
Laravel使用了很多魔术方法。你可以用这样的东西来解决这个问题。
class Product extends Model{
public function Reviews(){
return $this->hasMany(Review::class);
}
public functions getRatingAttribute(){
return $this->Reviews->avg('rate');
}
}
然后你可以这样访问...
Product::find(1)->rating;
所有上述解决方案都会导致N + 1问题。您可以在下面尝试以实现预先加载
namespace App;
use DB;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class Product extends Model
{
public function reviews()
{
return $this->hasMany('\App\Review');
}
public function ScopeAverageRating(Builder $query){
return $query->withCount(['reviews as average_rating' => function ($query) {
$query->select(DB::raw("avg(rate)"));
}]);
}
}
然后在您的控制器中,您可以使用App \ Product :: AverageRating()它将返回您可以在视图中迭代以获得average_rating的集合。