laravel - 即时加载集合
问题描述
我有这个,用户通过 pivot property_users 拥有多对多的属性。
我正在我的 web 应用程序中制作某种可重用的类。
这些是具有急切加载功能的模型:
//User model
public function properties()
{
return $this->belongsToMany(Property::class, 'property_users', 'user_id', 'property_id');
}
//Property model
public function property_users()
{
return $this->hasMany(PropertyUser::class, 'property_id', 'id');
}
//PropertyUser model
public function user()
{
return $this->belongsTo(User::class);
}
//GetProperties class
public function handle()
{
return auth()->user()->properties()->get();
}
//somewhere in a feature
$properties = $this->run(GetProperties::class);
//this returns valid properties under the logged in user
我现在需要在 property_users 中获取属于该用户的 chat_username
如果我遍历属性然后动态执行它,我设法使它工作。
$properties = $properties->map(function($property) {
$propertyUsers = $property->property_users()->get();
$chatUsername = null;
foreach($propertyUsers as $propertyUser) {
if($propertyUser->property_id == $property->id) {
$chatUsername = $propertyUser->chat_username;
}
}
return [
'name' => $property->name,
'id' => $property->id,
'chat_username' => $chatUsername
];
});
但我试图减少循环查询以减少命中,尤其是当它们位于数据库中的多个属性上时。
另一种方法是,我可以将 property_users 添加到 GetProperties 类下的即时加载中,方法是将其更新为:
$query = Property::query();
$query->with(['property_users']);
$query->whereHas('property_users', function($qry) {
$qry->where('user_id', Auth::user()->id);
});
$properties = $query->get();
return $properties;
但是我不想依赖于向原始的 GetProperties 类添加更多的急切加载,因为 GetProperties 会变胖而且我并不真正需要这些数据(比如说添加 property_invoices、property_schedules 等,但在某些区域并不真正需要它)。
相反,我想在运行中进行急切的加载,但要有所改变!这就是我的想象:
从属性中收集所有 id,使用 where 进行提取,并将所有用户应用于单个查询中的属性。这样会更漂亮。
也许是这样的:(使用原始的 GetProperties 类)
$properties = $this->run(GetProperties::class);
//this does not work. The error is: Method Illuminate\Database\Eloquent\Collection::property_users does not exist.
$property->property_users = $properties->property_users()->get();
如果有人能告诉我怎么做,那就太好了。
解决方案
只急切地加载您实际需要的字段怎么样?
$query->with('property_users:id,user_id');
该模型不会变胖,并且您不需要在循环中进行单独的查询。
它记录在官方文档中:https://laravel.com/docs/5.8/eloquent-relationships#eager-loading,请参阅Eager Loading Specific Columns
编辑:如果要在 GetProperties 类之后执行查询,则需要收集所有 id 并执行第二次查询。老实说,我不喜欢第二种方法,因为它要慢得多,性能较差,而且我认为它不如在 GetProperties 类中添加一行那么优雅,但它会起作用:
$properties = $this->run(GetProperties::class);
$ids = $properties->pluck('id'); // Get all the ids as an array
$propertyUsers = propertyUsers::whereIn('property_id', $ids)->get(); // Get the propertyUsers model
foreach($properties as $property) {
$property->property_users = $propertyUsers->where('property_id', $property->id); // Not even sure you can do that, proerty_users may not been writable
}
推荐阅读
- css - 无法覆盖引导程序来实现我自己的 CSS
- html - 当 div 存在于两者之间时,如何使用 nth-child 选择具有特定类的 div?
- reactjs - 在类组件中使用 TypeScript 和 Redux 进行编程式 React Router 导航
- javascript - 当redux中数据模型状态中的数据发生变化时,我无法在react中使用useeffect捕获更改事件
- r - 如何使用 yaml 标头覆盖默认 pandoc 选项以在 rmarkdown 中指定 Github Markdown?
- python - 如何注释条之间的差异?
- python - Flask-WTF 表单验证失败
- dragonruby-game-toolkit - 如何使用 DragonRuby 游戏工具包中的精灵表为“精灵”设置动画?
- python - 打开 .txt 文件并创建一个新的元组集合
- php - PHP Curl 请求不适用于 easypaisa 支付网关发布请求