我有一个称为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();
但是我总是遇到错误。
那么有可能在模型中做到这一点,或者还有其他方法吗? 任何帮助表示赞赏。
答案 0 :(得分:1)
您可以尝试以下操作:
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());
答案 1 :(得分:1)
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;
答案 2 :(得分:1)
最好使您的方法尽可能容易地定义关系。
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
给出有效值因此您可以相应地使用功能。
答案 3 :(得分:0)
所有上述解决方案均导致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。