查询 Laravel 中的集合

Querying collections in Laravel

我是否理解正确,当我查询 Laravel 集合时,它不会查询数据库,而是对已获取的内容执行查询?

例如,我有一个关系 returns 一个集合:

public function permissions()
{
    return $this->belongsToMany(Permission::class, RolePermission::getModelTable(), 'role_id', 'permission_id');
}

以下代码是查询数据库还是使用 php 工具处理集合?

$role->permissions->where('code','global.test')->count()

而且,据我所知,如果我查询关系,那么将查询数据库,而不是使用已经获取的结果:

$role->permissions()->where('code','global.test')->count()

所以基本上,$role->permissions - 使用获取的结果 "offline",但是 $role->permissions() - 查询数据库

什么方式通常更有效?什么时候?

你基本上是对的。调用 $role->permissions$role->permissions() 的区别在于第一个 returns 是 Collection 的实例,而第二个 returns 是 BelongsToMany 的实例。

Collection 是相关对象的集合(真的吗?),而 BelongsToMany 是关系本身。所以是的,通过调用方法(而不是魔术 属性),您正在查询数据库。

更新

我没听懂最后一个问题,抱歉。 第一次调用 $role->permissions(魔术 属性)时,Laravel 获取所有与 $role 关联的权限,如果它们不是 eager loaded。如果您只需要这些权限的一个子集,您可以使用任何魔术 属性 和方法来过滤它们。让我举一些例子。

$role = Role::first();
// Fetch all the permissions and count a subset.
$role->permissions->where('code', 'global.test')->count();
// Count another subset.
$role->permissions->where('code', 'another.test')->count();

同样可以使用以下方法完成:

$role = Role::first();
// Fetch a subset of the permissions and count it.
$role->permissions()->where('code', 'global.test')->count();
// Fetch another subset and count it.
$role->permissions()->where('code', 'another.test')->count();

如您所见,在第一个示例中,您只进行了一次查询并以不同方式过滤结果。在第二个示例中,您进行了两个查询。第一个显然效率更高

但是,如果您在同一次执行期间只需要一个子集,情况就会发生变化。这里我们使用 eager loading:

$role = Role::with('permissions', function($query) {
    // Here we filter the related permissions.
    $query->where('code', 'global.test');
})->first();
// We have what we want. No need to filter the collection.
$role->permissions->count();
// Let's do something else with this subset.
$role->permissions->all();

如果您获取所有相关对象,但只需要那个子集怎么办?

$role = Role::first();
// Filter the collection to count the needed subset.
$role->permissions->where('code', 'global.test')->count();
// Filter the collection to get the needed subset.
$role->permissions->where('code', 'global.test')->all();

大家可以看到,在第二个例子中我们就少了很多DRY,同样的操作也是多次进行。当然效率较低。