我发现一些查询结果真的出乎意料。
Laravel 5.2
我们有以下实体:
User
方法:
public function roles() : BelongsToMany
{
return $this->belongsToMany(Role::class)->withPivot('timestamp');
}
每个User
可以有多个角色,因此我们还有Role
个实体(但在我的问题中并不重要)和pivot
表格user_role
使用timestamp
字段(当然还有ID),因为我们保存有关时间的信息,User
何时达到特定角色。
我希望最后分配Users
Role
当我创建查询时(在某个存储库的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
,但只有User
最后一次获得Role
包含它!所有其他Users
的{{1}}字段都包含空数组。
为什么单独对每个roles
关系执行排序,但是当我添加Users
时,它的行为就像全局限制一样。
这让我发疯了......
感谢您的建议。
我已创建limit
方法以获取所有lastRoles()
有序的desc。但是所有,检索一个是不可能的。
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);
}
的最新Roles
的名称。
所以......在一个查询中无法做到这一点?这是唯一的方法吗?
答案 0 :(得分:0)
当您急切地加载与查询约束的关系时,查询将运行一次以加载所有关系,而不是单独加载每个关系。这是预期的行为。考虑一下,存在急切加载以将许多查询转换为一个查询以优化性能。只执行了一个查询,因此您的 def self.find_all_user_comments(user)
@comment_hash = []
@user_comments = Comment.where(user_id: user.id)
@user_comments.all.each do |co|
post = Post.find(co.commentable_id)
@comment_hash.push( { comment: co, post: post} )
end
@comment_hash
end
约束将限制整个结果集,而不是基于每个模型。
为避免这种情况,您可以尝试创建另一个添加所需限制约束的<div class="col-md-10 col-md-offset-1">
<h3>Recent comments:</h3>
<% if @comments.any? %>
<table class="table">
<thead>
<tr>
<th>Comment</th>
<th>Post</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% @comments.each do |co| %>
<tr class="comment-<%= co[:comment].id %>">
<td><%= truncate(co[:comment].body, length: 50) %></td>
<td><%= truncate(co[:post].title, length: 50) %></td>
<td><%= link_to "destroy", comment_path(co[:comment]), remote: true, method: :delete, data: {confirm: "Are you sure you want to delete this comment?"} %></td>
</tr>
<% end %>
</tbody>
</table>
<% end %>
</div>
方法。以下代码未经测试:
limit
假设这有效,您可以简单地将关系方法从belongsToMany
更改为public function lastRole() : BelongstoMany
{
return $this->belongsToMany(Role::class)
->withPivot('timestamp')
->orderBy('timestamp', 'desc')
->limit(1);
}
并删除您的查询约束:
roles
答案 1 :(得分:0)
为此,您需要一个帮助函数:
public function latestRole()
{
return $this->hasOne(Role::class)->withPivot('timestamp')->orderBy('timestamp', 'DESC');
}
然后:
$this->with('latestRole')->get();
对此awesome article的信任。