【问题标题】:Laravel eloquent relation table prefixLaravel 雄辩的关系表前缀
【发布时间】:2018-08-31 22:23:20
【问题描述】:

迟来的评论

这样做的唯一方法似乎是以 table_name_primary_key 格式定义外键列。如果它们不适合这种格式,那么如果不指定列名,关系就无法工作。

我正在尝试学习如何通过 reliese/laravel 代码生成器使用外键(它从数据库生成模型),但我遇到了一个问题,迫使我在生成的代码中重新指定所有外键名称代码。这是我的迁移代码和生成的关系代码:

//迁移

Schema::create('hotels', function(Blueprint $table) {
    $table->increments('hotel_id');
    $table->string('name', 64);
    $table->string('description', 512);
    $table->softDeletes();
    $table->timestamps();
});

Schema::create('floors', function(Blueprint $table){
    $table->increments('floor_id');
    $table->integer('hotel_id')->unsigned();
    $table->string('label', 128);
    $table->softDeletes();
    $table->timestamps();

    $table->foreign('hotel_id')->references('hotel_id')->on('hotels')->onDelete('cascade');
});

// 关系

// Hotel.php contains

public function floors()
{
    return $this->hasMany(\Otellier\Floor::class);
}

// Floor.php contains

public function hotel()
{
    return $this->belongsTo(\Otellier\Hotel::class);
}

现在,当我用 Faker 创建地板时:

$hotel = factory(App\Hotel::class)->make();
$floor = factory(App\Floor::class)->make([ "label" => "Floor #" . $floor_number ]);
$hotel->floors()->save($floor);

在最后一行,我得到这个错误:

Illuminate\Database\QueryException : SQLSTATE[42S22]: Column not found: 1054 Unknown column 'hotel_hotel_id' in 'field list' (SQL: insert into floors (label, hotel_hotel_id, updated_at, created_at) 值 (Floor #1, 8, 2018-03-22 12:37:39, 2018-03-22 12:37:39))

显然,它在floors 表中搜索hotel_hotel_id 字段作为列,我怀疑这是将表名添加为列名的前缀。为什么会发生这种情况,我该如何防止这种情况并强制整个系统不要为任何列添加前缀

不这样做:

public function hotel()
{
    return $this->belongsTo(\Otellier\Hotel::class, "hotels", "hotel_id", "hotel_id");
}

【问题讨论】:

  • 你有没有把hotel_id放在你$fillable属性Floor Model
  • 是的,它在模型中定义
  • laravel 通常在外键前面加上你要添加外键的表名
  • 但该错误与外键无关,与 Laravel 试图插入数据的列名有关。
  • 你所有的模型都扩展\Illuminate\Database\Eloquent\Model吗?你能改变它吗?

标签: laravel eloquent foreign-keys laravel-5.6


【解决方案1】:

Laravel 使用 Model.php 中的getForiegnKey() 方法来预测关系的外键。

/**
 * Get the default foreign key name for the model.
 *
 * @return string
 */
public function getForeignKey()
{
    return Str::snake(class_basename($this)).'_'.$this->primaryKey;
}

您可以在您的模型或基类覆盖它来改变它的行为。在您的情况下,它可以像这样使用,

public function getForeignKey()
{
    return $this->primaryKey;
}

当关系尝试 Io 访问对应的外键时,它将返回您的 $primaryKey 作为外键。

注意:如果您指定相关的外键,则此方法将不起作用。

【讨论】:

  • 可以,但是还是需要修改生成的模型文件。这是最近的顺便说一句。
  • 使用基类并在其中指定函数。
  • 不会还在修改模型文件吗?对不起,我想不修改任何核心文件或模型文件是没有办法的。
【解决方案2】:

默认情况下,eloquent 根据模型名称确定关系的外键。在这种情况下,Floor 模型被自动假定为具有hotel_id 外键。此外,Eloquent 假设外键的值应该与父级的 id(或自定义 $primaryKey)列匹配。换句话说,Eloquent 将在Floorhotel_id 列中查找酒店的id 列的值。如果您希望该关系使用id 以外的值,您可以传递第三个hasMany 方法的参数指定您的自定义 local key

public function floors()
{
    return $this->hasMany(\Otellier\Floor::class, 'hotel_id', 'hotel_id');
}

【讨论】:

  • 除了修改生成的类之外,我要求了一种方法。对不起。
  • 如果您认为我所说的是正确的并且可能对任何人有用,请为我的回答投票
【解决方案3】:

您需要在模型中定义自己的主键:

protected $primaryKey='floor_id';

对于另一个:

protected $primaryKey='hotel_id';

【讨论】:

  • 你有数据透视表吗?
  • 不,我使用数据透视表,但这不使用数据透视表。
  • 嗯,这就是一切都搞砸的原因。您可以尝试使用您更改的列的名称将第三个参数传递给那些函数。
  • 不,我将数据透视表用于多对多关系。这不需要一个,因为它需要一对多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-06
  • 2015-03-14
  • 2018-11-28
  • 2015-01-11
  • 2021-06-03
  • 2020-03-26
相关资源
最近更新 更多