首页 > 解决方案 > Laravel 一对多关系 - 对不存在字段的引用

问题描述

我忘记了在 Lavarel 进行迁移时,一旦关系像这样和曾经那样对我起作用?展示我想要得到的是我想为用户分配他的订单并订购他订购的产品。所以我有一个 User 表、Order 表和 OrderProduct 表。Usera 表与 Order 表具有一对多关系, Order 表与 OrderProduct 表具有一对多关系。从关系 Order 和 OrderProduct 开始,我得到一个错误:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'order_products_tables.order_table_id' in 'where clause' (SQL: select * from `order_products_tables` where `order_products_tables`.`order_table_id` = 1 and `order_products_tables`.`order_table_id` is not null)

这个错误清楚地表明他在 order_products_tables 表中找不到 order_table_id 列,我并不惊讶这听起来很傻,因为没有这样的字段但是有一个 order_id 字段,并且在迁移中描述了哪个字段是这种关系,我不明白为什么 Laravel 会尝试引用 order_products_tables。

迁移顺序:

Schema::create('order_tables', function (Blueprint $table) {
    $table->increments('id');

    $table->integer('user_id')->unsigned()->nullable();

    $table->foreign('user_id')
        ->references('id')
        ->on('users');

    $table->timestamps();
});

迁移订单产品:

Schema::create('order_products_tables', function (Blueprint $table) {
    $table->increments('id');

    $table->integer('order_id')->unsigned();

    $table->integer('count')->unsigned();
    $table->integer('price')->unsigned();

    $table->foreign('order_id')
        ->references('id')
        ->on('order_tables');

    $table->timestamps();
});

由于它是迁移的结果,order_products_tables 表存储来自 order_tables 表的记录 ID,并且关系基于该 ID。

型号订购表:

class OrderTable extends Model
{
    protected $table = 'order_tables';

    public function user()
    {
        return $this->belongsTo(User::class, 'id');
    }

    public function products()
    {
        return $this->hasMany('App\OrderProductTable');
    }
}

型号订购产品表:

class OrderProductTable extends Model
{
    protected $table = 'order_products_tables';

    public function order()
    {
        return $this->belongsTo(OrderTable::class, 'id');
    }
}

我不明白为什么要引用 order_table_id。我做过其他的关系,例如用户和订单,原理相同,它工作没有问题,突然这里我有这样的情况。我应该在哪里寻找解决方案,为什么会这样

标签: phplaravelone-to-manyrelation

解决方案


此错误来自使用错误的表名,或者更正确地说,是没有正确定义关系。以下关系定义将解决您的问题:

class OrderTable extends Model
{
    protected $table = 'order_tables';

    public function products()
    {
        return $this->hasMany('App\OrderProductTable', 'order_id', 'id');
    }
}

class OrderProductTable extends Model
{
    protected $table = 'order_products_tables';

    public function order()
    {
        return $this->belongsTo(OrderTable::class, 'order_id', 'id');
    }
}

您之前的代码不起作用的原因是 Laravel 使用默认值,这些默认值基本上是假设,并且要求您的数据库遵循某些命名约定。以下是您应遵循的约定列表*:

  • 表应该以复数形式的模型名称和snake_case命名:
    • 模型User应该有一个名为 的表users
    • 模型Category应该有一个名为categories(见英文复数)的表。
    • 模型AccountManager应该有一个名为 的表account_managers
  • 如果表没有模型,即多对多关系表,则表名应为单数形式和snake_case,其中包含关系的模型名称按字母顺序排列:
    • 如果存在模型Categoryand Product(带有表categoriesand products)并且它们之间存在多对多关系 ( belongsToMany()),则预计将调用数据透视表的表order_product(而不是product_order因为在字母表中o出现在前面)。p
  • 外键列应该在它们表示_id为后缀的模型之后被调用:
    • User例如,当在模型上引用模型时BlogPost,Laravel 期望将user_id列作为BlogPost模型上的外键。模型上引用的主键User取自默认情况下的$primaryKey属性。'id'

对于您的特定场景,这意味着我们需要以下模型、表格和列:

  • User具有表和列的模型,users如 Laravel 的默认迁移。
  • Order具有表格orders和列的模型,例如id, user_id, created_at, ...
  • Product具有表格products和列的模型,例如id, name, price, ...
  • OrderProduct具有表格order_products和列的模型,如id, order_id, product_id, quantity, ...

理论上,该模型OrderProduct是不必要的。$this->belongsToMany(Product::class)->withPivot('quantity')通过在Order模型和模型$this->belongsToMany(Order::class)->withPivot('quantity')上定义Product(注意枢轴字段),您还应该能够在没有它的情况下构建相同的系统。就个人而言,我更喜欢多对多关系的额外模型。

有关 Eloquent 关系的参考,请查看文档。当您需要覆盖关系的默认表或列名称时,有所有关系类型的示例和附加参数的附加信息。

* 此列表可能缺少重要信息。它是尽最大努力创建的。


推荐阅读