Laravel 自定义数据透视表关系和急切加载?

Posted

技术标签:

【中文标题】Laravel 自定义数据透视表关系和急切加载?【英文标题】:Laravel Custom Pivot Table relationship and eager loading? 【发布时间】:2014-09-11 12:16:10 【问题描述】:

我在为我的一个项目创建架构/模型时遇到问题,希望在这里获得一些帮助。

我目前有 3 个表:附件、产品和数据透视表 product_accessory

<?php 

Schema::create('accessories', function(Blueprint $table)

    $table->increments('id');


Schema::create('products', function(Blueprint $table) 

    $table->increments('id');


Schema::create('product_accessory', function(Blueprint $table)

    $table->increments('id');
    $table->integer('product_id')->unsigned();
    $table->integer('accessory_id')->unsigned();
    $table->foreign('product_id')->references('id')->on('products');
    $table->foreign('accessory_id')->references('id')->on('accessories');

现在的问题是我需要添加另一个最终取决于数据透视表关系的产品类型“适配器”,也就是说,适配器需要与产品和附件相关...

更新 这是我当前的 product_accessory_adaptor 表的样子

Schema::create('product_accessory_adaptor', function(Blueprint $table)

    $table->increments('id');
    $table->integer('product_accessory_id')->unsigned();
    $table->foreign('product_accessory_id')->references('id')->on('product_accessory');

这样,我可以拥有许多与产品和配件相关的适配器。我的问题是如何用 eloquent 建模这种关系?

这是我现在拥有的:

自定义枢轴模型:

class ProductAccessory extends Pivot 
   protected $table = 'product_accessory';

   public function product()
   
      return $this->belongsTo('Product');
   

   public function accessory()
   
     return $this->belongsTo('Accessory');
   

   public function adaptors() 
     return $this->hasMany('Adaptor', 'product_accessory_id'); 
    

产品及配件型号

class Accessory extends Eloquent 

   public function products()
   
      return $this->belongsToMany('Product', 'product_accessory', 'accessory_id', 'product_id')->withPivot();
   

   public function newPivot(Eloquent $parent, array $attributes, $table, $exists) 
   
      if ($parent instanceof Product) 
          return new ProductAccessory($parent, $attributes, $table, $exists);
      
      return parent::newPivot($parent, $attributes, $table, $exists);
   

   public function adaptors()
   
      return $this->hasManyThrough('Adaptor', 'ProductAccessory', 'accessory_id', 'product_accessory_id');
   


class Product extends Eloquent 

   public function accessories()
   
      return $this->belongsToMany('Accessory', 'product_accessory', 'product_id', 'accessory_id')->withPivot();
   

   public function newPivot(Eloquent $parent, array $attributes, $table, $exists) 
   
      if ($parent instanceof Accessory) 
          return new ProductAccessory($parent, $attributes, $table, $exists);
      
      return parent::newPivot($parent, $attributes, $table, $exists);
   

   public function adaptors()
   
      return $this->hasManyThrough('Adaptor', 'ProductAccessory', 'product_id', 'product_accessory_id');
   

适配器型号:

class Adaptor extends Eloquent 

   protected $table = 'product_accessory_adaptor';

   public function productAccessory() 
      return $this->belongsTo('ProductAccessory');
   

更新 现在模式和模型已设置。但是,使用 hasManyThrough 关系存在一些问题。此外,在这种情况下,有什么方法可以为枢轴关系(即适配器)进行预加载?

注意 当我在 Product 或 Accessory 模型上调用 adapters() 时发生的错误是 Argument 1 passed to Illuminate\Database\Eloquent\Relations\Pivot::__construct() must be an instance of Illuminate\Database\Eloquent\Model, none given, called in /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 872 and defined

【问题讨论】:

你需要这个:1 自定义枢轴模型ProductAccessory2 2 belongsTo 此模型上的关系(Product 和 @ 987654331@) + hasManyAdaptor 的关系,3 适配器模型与 belongsTo 与该枢轴模型的关系,4 hasManyThroughAdaptor 的关系开启ProductAccessory。它可能看起来很复杂,但请尝试一下。 嘿@deczo 感谢您的回复。我试图弄清楚如何编写自定义枢轴模型,但似乎无法找到关于它的示例。 laravel.com/docs/eloquent#working-with-pivot-tables 此处的文档并未真正提供有关如何执行此操作的示例。你介意给我一些指示吗? 【参考方案1】:

这就是你的支点:

<?php

use Illuminate\Database\Eloquent\Model as Eloquent;

// you don't need to call it ..Pivot, just my suggestion
class ProductAccessory extends Eloquent 

  protected $table = 'product_accessory';

  public function product()
  
    return $this->belongsTo('Product');
  

  public function accessory()
  
    return $this->belongsTo('Accessory');
  

  public function adaptors()
  
    return $this->hasMany('Adaptor', 'product_accessory_id');
  


// Product model
public function adaptors()

    return $this->hasManyThrough(
      'Adaptor', 'ProductAccessoryPivot', 'product_id', 'product_accessory_id'
    );


// Accessory model
public function adaptors()

    return $this->hasManyThrough(
      'Adaptor', 'ProductAccessoryPivot', 'accessory_id', 'product_accessory_id'
    );

现在示例用法:

$product = Product::first();

$product->adaptors; // collection of all adaptors for given product

$product->adaptors->first()->accessory; // accessory for single adaptor

$product->accessories; // collection of accessories, each with your custom pivot, so:

$product->accessories->first()->adaptors; // collection of adaptors for given product-accessory pair

... and more, try it

【讨论】:

嘿@deczo 我现在可以通过$product-&gt;accessories()-&gt;first()-&gt;pivot-&gt;adaptors() 访问适配器数据,但不能通过Product::first()-&gt;adaptors or $product-&gt;accessories-&gt;first()-&gt;adaptors. 访问,每当我这样做时,就会发生此错误:Argument 1 passed to Illuminate\Database\Eloquent\Relations\Pivot::__construct() must be an instance of Illuminate\Database\Eloquent\Model, none given, called in /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 872 and defined 另外,附带说明一下,无论如何我可以急切地加载适配器数据吗? 对,我忘了。其实你不需要扩展Pivot而是普通的Model/Eloquent,也不需要使用自定义的newPivot。检查编辑,它会工作。 太好了,终于成功了!多谢。而且我能够对适配器使用急切加载,基本上将查询速度减半。 对不起,改成这种方法后,我的适配器保存现在不起作用...我应该如何将适配器添加到数据透视表? 好的,您仍然需要自定义数据透视表才能以您想要的方式使用它:laravel.io/bin/eybn6

以上是关于Laravel 自定义数据透视表关系和急切加载?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 急切加载特定列错误

Laravel 渴望加载数据透视表关系

Laravel 使用自定义查询预加载嵌套关系

带有嵌套关系的 Laravel 急切加载

Eloquent ORM / Laravel - 使用自定义数据透视表结构

Laravel 急切加载限制