我有以下型号: CardBoard,User,UserPricingPlans,PricingPlanLimits
注意:不要介意模型代码是否有问题。他们工作正常。
纸板
class CardBoard extends Model{
public function user(){
return $this->belongsTo('Models\User','id_user');
}
}
用户
class User extends Model{
public function pricingPlans(){
return $this->hasMany('Models\UserPricingPlan','id_user');
}
}
PricingPlan
class PricingPlan extends Model{
public function limits(){
return $this->hasOne('Models\PricingPlanLimits','id_pricing_plan','id_pricing_plan');
}
}
PricingPlanLimits
我没有描述该模型,它不是问题的必要条件。但请记住,有一个名为 maxBoards 的属性。
问题是我只能使用 CardBoard 模型实例,我想从PricingPlanLImits获取 maxBoard 属性。所以我这样做了:
注意:我已经有了CardBoard模型实例!
$maxBoard = $cardBoard->user->pricingPlans->last()->limits->maxBoard;
return $maxBoard;
上面的代码运行良好,但此操作生成的查询数量对我来说是开销。 Eloquent为每个关系做了 SELECT ,并且我不想要所有这些数据和操作。
{
"query": "select * from `users` where `users`.`id_user` = ? limit 1",
"bindings": [
],
"time": 0.96
}
{
"query": "select * from `users_princing_plan` where `users_princing_plan`.`id_user` = ? and `users_princing_plan`.`id_user` is not null",
"bindings": [
],
"time": 0.8
}
{
"query": "select * from `pricing_plan_limits` where `pricing_plan_limits`.`id_pricing_plan` = ? and `pricing_plan_limits`.`id_pricing_plan` is not null limit 1",
"bindings": [
],
"time": 0.88
}
是不是有办法优化这个并以Eloquent-Way运行更少的查询?
答案 0 :(得分:0)
答案 1 :(得分:0)
之前的评论与此解决方案并不太相关......
示例强>
$cardboard->user()->whereHas('pricingPlans', function ($plans) {
$plans->selectRaw('price_plan_limits.id, MAX(price_plan_limits.maxBoard) as MB'))
->from('price_plan_limits')
->where('price_plan_limits.id', 'price_plan.id')
->orderBy('MB', 'DESC')
})->get();
答案 2 :(得分:0)
我通常按相反顺序行事:
$maxBoard = PricingPlanLimits::whereHas(function($q)use($cardBoard){
$q->whereHas('PricingPlan', function($q1)use($cardBoard){
$q1->whereHas('User', function($q2)use($cardBoard){
$q2->whereHas('CardBoard', function($q3)use($cardBoard){
$q3->where('id', $cardBoard['id']);
});
});
// Probably you have to improve this logic
// It is meant to select select the last occurrence
$q1->orderBy('created_at', 'desc');
$q1->limit(1);
});
})->first()['maxBoard'];
完全未经测试,但这应该是在一个查询中实现目标的正确方法。
答案 3 :(得分:0)
您可以通过使用hasManyThrough关系来减少调用次数(请参阅:https://laravel.com/docs/5.4/eloquent-relationships#has-many-through)。
在这种情况下,你会有像
这样的东西class CardBoard extends Model{
public function userPricingPlans(){
return $this->hasManyThrough('Models\UserPricingPlan', 'Models\User', 'id_user', 'id_user');
}
}
然后你可以这样称呼它:
$maxBoard = $cardBoard->userPricingPlans->last()->limits->maxBoard;
要在一个查询中完成所有这一切,您需要流畅而真实的SQL连接,不能用雄辩的方式完成(但是你会错过所有的ORM乐趣)
答案 4 :(得分:0)
通常,通过3个查询来获得结果是完全可以的,类似的查询通常需要10毫秒。但是您的每个查询都花了将近1秒,这太长了。我不知道为什么。
尽管您也可以通过单个查询获得相同的结果。
您的命名有点不合常规。我使用了一种比较流行的命名约定,希望您可以将其应用于您的案例。
class CardBoard extends Model
{
protected $table = 'card_boards';
public function user()
{
return $this->belongsTo(User::class,'user_id');
}
}
class User extends Model
{
protected $table = 'users';
public function pricingPlans()
{
return $this->hasMany(UserPricingPlan::class,'user_id');
}
}
class PricingPlan extends Model
{
protected $table = 'pricing_plans';
// This is a one to one relationship so I use a singular form.
public function limit()
{
return $this->hasOne(PricingPlanLimit::class,'pricing_plan_id');
}
}
class PricingPlanLimit extends Model
{
protected $table = "pricing_plan_limits";
}
获取结果的查询:
$carboardId = 100;
$latestPricingPlanSubQuery = PricingPlan::select('pricing_plans.*', DB::raw('MAX(created_at) as last_post_created_at'))
->groupBy('user_id');
$carboard = Carboard::select('card_boards.*', 'pricing_plan_limits.max_board')
->join('users', 'cardboards.user_id', '=', 'users.id')
->joinSub($latestPricingPlans, 'latest_pricing_plans', function ($join){
$join->on('users.id', '=', 'latest_pricing_plans.user_id');
})
->join('pricing_plan_limits', 'latest_pricing_plans.id', '=', 'pricing_plan_limits.pricing_plan_id')
->find($cardboardId);
关键是要有一个子查询,它仅获取每个用户的最新定价计划。