laravel - 从eloquent模型中获取单个值,以单个字段的形式导入数据

问题描述 投票:2回答:4

我有一个名为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();

但我最终会遇到错误..

那么有可能在模型中做到这一点还是有其他方式?任何帮助表示赞赏。

laravel eloquent model
4个回答
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的值
  • 如果值超过2个小数点(大多数为4),则以3.9265格式给出有效值

所以你可以相应地使用你的功能。


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
投票

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;

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的集合。

© www.soinside.com 2019 - 2024. All rights reserved.