Laravel 预先加载按关系排序
Laravel eager loading sort by relationship
我有一些关系(希望我能正确解释)并且需要根据本质上是远距离关系对输出进行排序。
我有一个枢轴 table,其中包含许多关系的详细信息,包括我要排序的关系。
--User.php
public function players()
{
return $this->belongsToMany('App\Models\Player', 'league_player_user')->withPivot('position_id');
}
--Player.php
public function position()
{
return $this->belongsToMany('App\Models\Position', 'league_player_user');
}
我会迫不及待地加载这样的关系;
$user = User::with('players')->where('id', Auth::user()->id)->first();
所以,我想我想做这样的事情(不起作用)。
$user = User::with(['players' => function($q){
$q->orderBy('position.sort_id', 'asc');
}])->where('id', Auth::user()->id)->first();
关键的 Table 结构看起来有点像这样;
league_player_user.
...league_id
...player_id
...user_id
...position_id
头寸 table 包含 sort_id
希望这些信息足够了,如果需要请索取更多信息。非常感谢。
好的,所以您正在尝试获取单个用户,但他们的玩家(其中用户 bTM 玩家)已经填充并按位置排序(其中 pivot bT 位置)。
在这种情况下,如果不进行修改,您将无法使用 Laravel 的内置关系方法,因为 Laravel 并不是为了处理枢轴上的关系而构建的 table 其他关系。幸运的是,ORM 足够灵活,允许您通过 'manual' 连接来做您想做的事。
所以直接回答你的问题,这是你需要的代码(你真的很接近!):
$user = User::with(['players' => function ($q) {
$q->join('position', 'league_player_user.position_id', '=', 'position.id')
->orderBy('position.sort_id', 'asc');
}])->where('id', Auth::user()->id)->first();
但是,在我看来,这不是很好的代码,原因如下:
- 您正在手动获取授权用户(当
Auth::user()
所以方便时)
- 您实际上必须从模型中获取特定于实现的逻辑(枢轴 table 被称为
league_player_user
并将其放置的事实......好吧无论它在哪里(您的控制器?)
- 这只会影响这一个查询 - 如果您碰巧通过其他方式获得
User
(例如 Auth::user()
或 User::find(1)
或其他方式),您将无法获得玩家正确排序
因此,为了使您的查询更简单,我建议您不要急于加载播放器。因此,您需要预先做的是:
$user = Auth::user();
现在,在关系(User
class 中的 players() 方法)上,您进行特殊排序工作:
public function players()
{
return $this->belongsToMany('App\Models\Player', 'league_player_user')
->withPivot('position_id')
->join('position', 'league_player_user.position_id', '=', 'position.id')
->orderBy('position.sort_id');
}
这样,任何时候您调用 $user->players
,您都会得到正确的排序。
我必须补充一点,这样做可能不允许您预先加载玩家,因为 Laravel 的预先加载(即在 ORM 链中使用 ->with()
)由于Laravel 执行预先加载查询的方式 - 一个用于主查询(即用户),一个用于关系(即玩家),但它执行此查询以获得所有结果,因此无法使用特殊的订购系统可能。你必须看看你是否真的关心 eager loading 玩家。在您上面的情况下(您获得单一授权用户的情况),我认为预加载并不那么重要。
编辑以添加有关预加载的说明:
我建议预先加载可能不起作用的原因是 Laravel 中的预先加载有点像这样:假设您有类别和产品:Category
hM Product
, Product
bT Category
。要获得一个类别,您可以使用 $category = Category::find(1)
和 Laravel 将其转换成一个有点像这样的查询:SELECT * FROM `categories` WHERE `id` = '1'
。如果您随后调用 $category->products
Laravel 将发出 SELECT * FROM `products` WHERE `category_id` = '1'
。这是明智的。但是如果你有下面的代码,那就更糟了:
<?php $categories = Category::all(); ?>
<ul>
@foreach ($categories as $category)
<li>Category {{{ $category->name }}} contains {{{ $category->products->count() }}} products.</li>
@endforeach
</ul>
在那种情况下,您会有以下查询:
SELECT * FROM `categories`;
SELECT * FROM `products` WHERE `category_id` = '1';
SELECT * FROM `products` WHERE `category_id` = '2';
SELECT * FROM `products` WHERE `category_id` = '3';
... as many categories as you had
但是,如果您要将第一行更改为:
<?php $categories = Category::with('products')->get(); ?>
现在您只有两个查询:
SELECT * FROM `categories`;
SELECT * FROM `products` WHERE `category_id` IN ('1', '2', '3', ...);
Laravel 然后,在调用第二个查询后,将根据它知道的您拥有的类别 ID 为您创建各种集合。
然而,这是简单化的关系案例。在你的情况下,products()
方法不仅仅是 return $this->hasMany('Product');
,它还包括一个数据透视表和一个手动连接等,并且第二个查询(即急切加载查询)可能不会'无法正确处理和执行该排序。
正如我所说,我不确定它是如何工作的,这对我来说只是一个危险信号。一定要试一试,看看你会得到什么 - 你可能会发现它适合你。
我有一些关系(希望我能正确解释)并且需要根据本质上是远距离关系对输出进行排序。
我有一个枢轴 table,其中包含许多关系的详细信息,包括我要排序的关系。
--User.php
public function players()
{
return $this->belongsToMany('App\Models\Player', 'league_player_user')->withPivot('position_id');
}
--Player.php
public function position()
{
return $this->belongsToMany('App\Models\Position', 'league_player_user');
}
我会迫不及待地加载这样的关系;
$user = User::with('players')->where('id', Auth::user()->id)->first();
所以,我想我想做这样的事情(不起作用)。
$user = User::with(['players' => function($q){
$q->orderBy('position.sort_id', 'asc');
}])->where('id', Auth::user()->id)->first();
关键的 Table 结构看起来有点像这样;
league_player_user.
...league_id
...player_id
...user_id
...position_id
头寸 table 包含 sort_id
希望这些信息足够了,如果需要请索取更多信息。非常感谢。
好的,所以您正在尝试获取单个用户,但他们的玩家(其中用户 bTM 玩家)已经填充并按位置排序(其中 pivot bT 位置)。
在这种情况下,如果不进行修改,您将无法使用 Laravel 的内置关系方法,因为 Laravel 并不是为了处理枢轴上的关系而构建的 table 其他关系。幸运的是,ORM 足够灵活,允许您通过 'manual' 连接来做您想做的事。
所以直接回答你的问题,这是你需要的代码(你真的很接近!):
$user = User::with(['players' => function ($q) {
$q->join('position', 'league_player_user.position_id', '=', 'position.id')
->orderBy('position.sort_id', 'asc');
}])->where('id', Auth::user()->id)->first();
但是,在我看来,这不是很好的代码,原因如下:
- 您正在手动获取授权用户(当
Auth::user()
所以方便时) - 您实际上必须从模型中获取特定于实现的逻辑(枢轴 table 被称为
league_player_user
并将其放置的事实......好吧无论它在哪里(您的控制器?) - 这只会影响这一个查询 - 如果您碰巧通过其他方式获得
User
(例如Auth::user()
或User::find(1)
或其他方式),您将无法获得玩家正确排序
因此,为了使您的查询更简单,我建议您不要急于加载播放器。因此,您需要预先做的是:
$user = Auth::user();
现在,在关系(User
class 中的 players() 方法)上,您进行特殊排序工作:
public function players()
{
return $this->belongsToMany('App\Models\Player', 'league_player_user')
->withPivot('position_id')
->join('position', 'league_player_user.position_id', '=', 'position.id')
->orderBy('position.sort_id');
}
这样,任何时候您调用 $user->players
,您都会得到正确的排序。
我必须补充一点,这样做可能不允许您预先加载玩家,因为 Laravel 的预先加载(即在 ORM 链中使用 ->with()
)由于Laravel 执行预先加载查询的方式 - 一个用于主查询(即用户),一个用于关系(即玩家),但它执行此查询以获得所有结果,因此无法使用特殊的订购系统可能。你必须看看你是否真的关心 eager loading 玩家。在您上面的情况下(您获得单一授权用户的情况),我认为预加载并不那么重要。
编辑以添加有关预加载的说明:
我建议预先加载可能不起作用的原因是 Laravel 中的预先加载有点像这样:假设您有类别和产品:Category
hM Product
, Product
bT Category
。要获得一个类别,您可以使用 $category = Category::find(1)
和 Laravel 将其转换成一个有点像这样的查询:SELECT * FROM `categories` WHERE `id` = '1'
。如果您随后调用 $category->products
Laravel 将发出 SELECT * FROM `products` WHERE `category_id` = '1'
。这是明智的。但是如果你有下面的代码,那就更糟了:
<?php $categories = Category::all(); ?>
<ul>
@foreach ($categories as $category)
<li>Category {{{ $category->name }}} contains {{{ $category->products->count() }}} products.</li>
@endforeach
</ul>
在那种情况下,您会有以下查询:
SELECT * FROM `categories`;
SELECT * FROM `products` WHERE `category_id` = '1';
SELECT * FROM `products` WHERE `category_id` = '2';
SELECT * FROM `products` WHERE `category_id` = '3';
... as many categories as you had
但是,如果您要将第一行更改为:
<?php $categories = Category::with('products')->get(); ?>
现在您只有两个查询:
SELECT * FROM `categories`;
SELECT * FROM `products` WHERE `category_id` IN ('1', '2', '3', ...);
Laravel 然后,在调用第二个查询后,将根据它知道的您拥有的类别 ID 为您创建各种集合。
然而,这是简单化的关系案例。在你的情况下,products()
方法不仅仅是 return $this->hasMany('Product');
,它还包括一个数据透视表和一个手动连接等,并且第二个查询(即急切加载查询)可能不会'无法正确处理和执行该排序。
正如我所说,我不确定它是如何工作的,这对我来说只是一个危险信号。一定要试一试,看看你会得到什么 - 你可能会发现它适合你。