laravel Eager Loading:在具有雄辩关系的枢轴上使用`with`
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37572231/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Eager Loading: Use `with` on pivot with eloquent relationship
提问by rap-2-h
There are 4 tables:
有4张表:
bundles
: id, nameproducts
: id, nameprices
: id, namebundle_product
: id, bundle_id, product_id, price_id
bundles
:身,姓名products
:身,姓名prices
:身,姓名bundle_product
: id, bundle_id, product_id, price_id
There are 3 models:
有3种型号:
Bundle
Product
Price
Bundle
Product
Price
A Product
has a Price
when in a Bundle
. I want to have all bundles
with their associated products
and associated prices
.I can get all bundles with their product and the price id:
A在 a 中Product
有一个Price
when Bundle
。我想把所有的都bundles
与他们的关联products
和关联prices
。我可以获得他们的产品和价格 ID 的所有捆绑包:
// I created a Bundle Model with a products method
class Bundle extends Model
{
public function products()
{
return $this->belongsToMany(Product::class)->withPivot('price_id');
}
}
// Then I call this in a controller
$all_bundles = Bundle::with('products')->get();
// Then I can get the price Id of the first product of the first bundle
$price_id = Bundle::with('products')->first()
->products()->first()
->pivot->price_id;
But I dont want the price id, I want the price Model. Is there any way to preload the price from the pivot (with Eager Loading)?
但我不想要价格 id,我想要价格 Model。有没有办法从枢轴预加载价格(使用 Eager Loading)?
采纳答案by rap-2-h
One solution could be adding a BundleProduct
model for the pivot. Then link the BundleProduct object to Bundle model:
一种解决方案可能是BundleProduct
为枢轴添加模型。然后将 BundleProduct 对象链接到 Bundle 模型:
class Bundle extends Model
{
public function bundleProducts()
{
return $this->hasMany(BundleProduct::class, 'bundle_id', 'id');
}
}
To get all your bundles with their associated products and prices in this bundle, just do:
要在此捆绑包中获取所有捆绑包及其相关产品和价格,只需执行以下操作:
Bundle::with('bundleProducts.product', 'bundleProducts.price')->get();
That worked for me, hope it could help someone else.
这对我有用,希望它可以帮助别人。
回答by Arjon Jason Castro
The current accepted answer deviates from the original data structure. I created a package which can help you achieve what you want and also it maintains the original data structure. Please read my medium story here: https://medium.com/@ajcastro29/laravel-eloquent-eager-load-pivot-relations-dba579f3fd3a
当前接受的答案偏离了原始数据结构。我创建了一个包,它可以帮助你实现你想要的,并且它维护了原始数据结构。请在这里阅读我的媒体故事:https: //medium.com/@ajcastro29/laravel-eloquent-eager-load-pivot-relations-dba579f3fd3a
First, create your custom pivot model and define relations on pivot model, in your case:
首先,创建您的自定义枢轴模型并在枢轴模型上定义关系,在您的情况下:
use Illuminate\Database\Eloquent\Relations\Pivot;
class BundleProduct extends Pivot
{
public function price()
{
return $this->belongsTo(Price::class);
}
}
Then use the pivot model in the relation:
然后在关系中使用枢轴模型:
class Bundle extends Model
{
public function products()
{
return $this->belongsToMany(Product::class)
->withPivot('price_id') // this is needed to query the relation `price`
->using(BundleProduct::class);
}
}
Make sure you use the trait AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait
in the Product
model because it is the related model in belongsToMany relation. This let us enable eager loading the pivot relations.
确保AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait
在Product
模型中使用特征,因为它是belongsToMany 关系中的相关模型。这让我们能够预先加载枢轴关系。
use AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait;
class Product extends Model
{
use EagerLoadPivotTrait;
}
Then eager load it like this:
然后像这样急切加载它:
$bundle = Bundle::with('products.pivot.price')->first();
$price = $bundle->products->first()->pivot->price;
回答by JaffParker
Documentation: Eloquent: Relationships: Many To Many
文档:雄辩:关系:多对多
By default, only the model keys will be present on the pivot object. If your pivot table contains extra attributes, you must specify them when defining the relationship:
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
默认情况下,只有模型键会出现在枢轴对象上。如果数据透视表包含额外的属性,则必须在定义关系时指定它们:
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
That means that the withPivot()
method only adds missing fields to the pivot
object. To retrieve the actual Price
model you will have to set up another relationship. It would look something like this:
这意味着该withPivot()
方法只会向pivot
对象添加缺失的字段。要检索实际Price
模型,您必须建立另一个关系。它看起来像这样:
/**
* Class Bundle
*
* Bundle model with the products relationship
*/
class Bundle extends Model
{
public function products()
{
return $this->belongsToMany(Product::class);
}
}
/**
* Class Product
*
* Product model with the prices relationship
*/
class Product extends Model
{
public function prices()
{
return $this->belongsToMany(Price::class);
}
}
/**
* Class Price
*
* Simple model, end result
*/
class Price extends Model
{
// Model definition...
}
This is basic and of course not the complete code, only the functions necessary for the answer.
这是基本的,当然不是完整的代码,只有答案所需的功能。
After this all you need to do to retrieve relationships is the following:
在此之后,您需要做的就是检索关系如下:
// You can query a child relationship using the dot (.). Prices collection will be accessible within each member of the products collection
$all_bundles = Bundle::with('products.prices')->get();
$price_id = $all_bundles->first()
->products->first()
->prices->first()->id;
回答by Kieran Smith
I think you'll struggle for a way to load the price model with eager loading alone, unless there is a way to pass a parent (the product, in this case) into a closure - which I'm pretty sure there isn't.
我认为您会很难找到一种单独使用预先加载来加载价格模型的方法,除非有办法将父级(在本例中为产品)传递到闭包中 - 我很确定没有.
$all_bundles = Bundle::with(['products.prices' => function($query) use (PARENT) {
$query->where('id', PARENT->pivot->price_id);
}])->get();
You could do this to load only the relevant price model, rather than all price models, after the initial query though:
您可以执行此操作以在初始查询后仅加载相关价格模型,而不是所有价格模型:
$all_bundles = Bundle::with('products')->get();
foreach($all_bundles as $bundle) {
foreach($bundle->products as $product) {
$product->load(['prices' => function($query) use ($product) {
$query->where('id', $product->pivot->price_id);
}]);
}
}