我发现一些查询结果真的很出乎意料。
这是拉拉维尔 5.2
我们有以下实体:
User
方法:
public function roles() : BelongsToMany
{
return $this->belongsToMany(Role::class)->withPivot('timestamp');
}
每个User
可以有很多角色,所以我们也有Role
实体(但在我的问题中并不重要(和pivot
表user_role
timestamp
字段(当然还有 id(,因为我们持有有关时间的信息,当User
获得特定角色时。
我想用他们上次分配的Role
获得所有Users
当我创建查询(在某些存储库User
上下文中(时:
$this->with(['roles' => function($query) {
$query->orderBy('timestamp', 'desc');
}])->all();
结果将包含Users
,其中Roles
实体按时间戳排序 - 没关系。但是我只想检索每个User
实体中的最后一个角色,而不是全部排序。
所以。。。
$this->with(['roles' => function($query) {
$query->orderBy('timestamp', 'desc')->limit(1);
}])->all();
然后我检索Users
但只有最后一次达到一些Role
的User
包含它!所有其他Users
的roles
字段都包含空数组。
为什么分别对每个Users
关系执行排序,但是当我添加limit
时,它的行为就像对所有关系的全局限制。
这让我发疯...
谢谢你的建议。
编辑
我已经创建了lastRoles()
方法来获取所有Roles
有序描述。但是,检索一个是不可能的。
public function lastRoles() : BelongsToMany
{
return $this->BelongsToMany(Roles::class)->withPivot('timestamp')->latest('timestamp');
}
对于测试:
$users = (new User())->with('lastRoles')->get();
但现在我必须遍历Users
并调用每个lastRoles()
:
foreach ($users as $user) {
var_dump($user->lastRoles()->get()->first()->name);
}
然后我检索分配给每个User
的最新Roles
的名称。
所以。。。没有办法在一个查询中做到这一点?这是唯一的办法?
要使其正常工作,您需要一个辅助函数:
public function latestRole()
{
return $this->hasOne(Role::class)->withPivot('timestamp')->orderBy('timestamp', 'DESC');
}
然后:
$this->with('latestRole')->get();
感谢这篇很棒的文章。
当您急切加载具有查询约束的关系时,查询将运行一次以加载所有关系,而不是单独加载每个关系。这是预期行为。想想看,存在将许多查询转换为一个查询以优化性能的急切加载。只执行一个查询,因此limit
约束将限制整个结果集,而不是基于每个模型。
为了规避这种情况,您可以尝试创建另一个belongsToMany
方法来添加所需的极限约束。以下代码未经测试:
public function lastRole() : BelongstoMany
{
return $this->belongsToMany(Role::class)
->withPivot('timestamp')
->orderBy('timestamp', 'desc')
->limit(1);
}
假设这有效,则可以简单地将关系方法从roles
更改为lastRole
并删除查询约束:
$this->with('lastRole')->all();