急切加载:在具有雄辩关系的枢轴上使用“with”

2022-08-30 23:26:54

有4张桌子:

  • bundles:id,名称
  • products:id,名称
  • prices:id,名称
  • bundle_product:id, bundle_id, product_id, price_id

有3种型号:

  • Bundle
  • Product
  • Price

A 在 .我想拥有所有与他们的相关和关联的价格我可以获得所有捆绑包及其产品和价格ID:ProductPriceBundlebundlesproducts

// 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;

但是我不想要价格ID,我想要价格模型。有没有办法从枢轴预加载价格(使用急切加载)?


答案 1

当前接受的答案偏离了原始数据结构。我创建了一个包,可以帮助您实现所需的目标,并保持原始数据结构。请在这里阅读我的媒体故事:https://medium.com/@ajcastro29/laravel-eloquent-eager-load-pivot-relations-dba579f3fd3a

首先,创建自定义透视模型并在透视模型上定义关系,在您的例子中:

use Illuminate\Database\Eloquent\Relations\Pivot;

class BundleProduct extends Pivot
{
    public function price()
    {
        return $this->belongsTo(Price::class);
    }
}

然后在关系中使用透视模型:

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);
    }
}

请确保在模型中使用该特征,因为它是属于 ToMany 关系中的相关模型。这让我们能够预先加载枢轴关系。AjCastro\EagerLoadPivotRelations\EagerLoadPivotTraitProduct

use AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait;

class Product extends Model 
{
  use EagerLoadPivotTrait;
}

然后急切地加载它,如下所示:

$bundle = Bundle::with('products.pivot.price')->first();
$price = $bundle->products->first()->pivot->price;

答案 2

一种解决方案是为透视添加一个模型。然后将捆绑产品对象链接到捆绑模型:BundleProduct

class Bundle extends Model
{
    public function bundleProducts()
    {
        return $this->hasMany(BundleProduct::class, 'bundle_id', 'id');
    }
}

要在此捆绑包中获取所有捆绑包及其相关产品和价格,只需执行以下操作:

Bundle::with('bundleProducts.product', 'bundleProducts.price')->get();

这对我有用,希望它可以帮助别人。


推荐