我正在与Laravel 5合作,我遇到了让->wherePivot()
处理多对多关系的问题。当我dd()
SQL时,看起来Eloquent正在使用`pose_state`来查找数据透视表中的记录.`pose_id`为null`。
我希望这是一个简单的错误而不是错误。任何想法都表示赞赏。
姿势
id
name
type
状态
id
name
machine_name
pose_state
pose_id
state_id
status
姿
<?php namespace App;
use DB;
use App\State;
use Illuminate\Database\Eloquent\Model;
class Pose extends Model {
public function states()
{
return $this->belongsToMany('App\State')
->withPivot('status_id')
->withTimestamps();
}
public function scopeWithPendingReviews()
{
return $this->states()
->wherePivot('status_id',10);
}
}
国家
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class State extends Model {
public function poses()
{
return $this->belongsToMany('Pose')
->withPivot('status_id')
->withTimestamps();
}
}
PosesController功能
public function listPosesForReview(){
$poses = Pose::withPendingReviews()->get();
dd($poses->toArray() );
}
SQL
select
`states`.*, `pose_state`.`pose_id` as `pivot_pose_id`,
`pose_state`.`state_id` as `pivot_state_id`,
`pose_state`.`status_id` as `pivot_status_id`,
`pose_state`.`created_at` as `pivot_created_at`,
`pose_state`.`updated_at` as `pivot_updated_at`
from
`states` inner join `pose_state` on `states`.`id` = `pose_state`.`state_id`
where
`pose_state`.`pose_id` is null and `pose_state`.`status_id` = ?
当我更新我的代码以删除其工作的范围时。感谢@Deefour让我走上了正确的道路!也许范围还有其他我不想要的东西。
public function pendingReviews()
{
return $this->states()
->wherePivot('status_id','=', 10);
}
我终于开始工作了。上面的解决方案给了我重复的条目。不知道为什么会这样,但确实如此,所以我会坚持下去。
public function scopeWithStatusCode($query, $tag)
{
$query->with(['states' => function($q) use ($tag)
{
$q->wherePivot('status_id','=', $tag);
}])
->whereHas('states',function($q) use ($tag)
{
$q->where('status_id', $tag);
});
}
答案 0 :(得分:2)
我认为您对scopeWithPendingReviews()
的实施是滥用范围的预期用途。
除此之外,我相信您并没有正确使用wherePivot()
。根据 the source ,方法签名为
public function wherePivot($column, $operator = null, $value = null, $boolean = 'and')
但你将其视为
public function wherePivot($column, $value = null, $boolean = 'and')
这意味着
->wherePivot('status_id',10)
应该是
->wherePivot('status_id', '=', 10)
范围应该被视为可附加到现有查询的可重用条件集,即使该查询只是
SomeModel::newQuery()
这个想法是,预先存在的查询将通过范围方法中的条件进一步细化(读取:&#39;范围&#39;),而不是生成新的查询,并且绝对不会生成新的查询基于相关模型的查询。
默认情况下,传递给scope方法的第一个也是唯一的参数是查询构建器实例本身。
您的Pose
模型上的范围实施实际上只是在您执行此操作后对states
表进行查询
$this->states()
这就是你的SQL出现的原因。它也是一个明确的指标,你滥用范围。范围可能看起来像这样
public function scopeWithPendingReviews($query) {
$query->join('pose_state', 'poses.id', '=', 'pose_state.pose.id')
->where('status_id', 10);
}
与基于pendingReviews()
模型返回查询的新State
方法不同,此范围将优化Pose
模型上的查询。
现在您可以按原定使用范围。
$poses = Pose::withPendingReviews();
可以翻译成更详细的
$poses = Pose::newQuery()->withPendingReviews();
另请注意,上述范围不会返回值。它接受现有的查询构建器对象并添加到其上。
这个问题的另一个答案充满了错误的信息。
wherePivot()
。withTimestamps()
的使用与您的问题完全无关withTimestamps()
调用就可以了。只需确保您的联接表中有created_at
和updated_at
列。答案 1 :(得分:2)
我认为你的范围实现很好,我看到的问题只是一个错字。您的架构显示该字段名为status
,但您的where条件是指status_id
尝试:
->wherePivot('status', 10);
此外,withTimestamps()
方法导致问题。您的模式中没有时间戳用于数据透视表(我可以看到),因此您不应将这些时间戳放在关系定义中,因为它正在尝试获取与创建/更新关系时相关的时间戳。如果您将数据透视表模式设置为具有时间戳字段,则可以执行此操作,但我认为您必须执行一些自定义工作才能使时间戳正确保存。
答案 2 :(得分:1)
这对我有用(Laravel 5.3):
$task = App\Models\PricingTask::find(1);
$task->products()->wherePivot('taggable_type', 'product')->get();
答案 3 :(得分:0)
如果您在wherePivot
中使用的列尚未添加到withPivot
,您也可能会遇到此问题(不返回任何结果)。