Laravel 5.6 OneToOne 关系不起作用

Posted

技术标签:

【中文标题】Laravel 5.6 OneToOne 关系不起作用【英文标题】:Laravel 5.6 OneToOne relation not working 【发布时间】:2019-04-18 17:39:48 【问题描述】:

我有一个 BuildingImage 模型,它与 BuildingType 具有 OneToOne 关系:

BuildImage 模型:

/**
 * Get the source type of the Building Image.
 */
public function type()

    return $this->hasOne('App\BuildingType');

建筑类型模型:

/**
 * Get the Building Image that owns the building type.
 */
public function buildingImage()

    return $this->belongsTo('App\BuildingImage');

我的桌子:

building_images 表 -> source 是建筑类型 id

building_types 表

当我尝试在我的控制器中执行此操作只是为了测试时: (一个 ImageRequest 有一个或多个建筑,一个建筑有一个 BuildingType)

$imageRequest = ImageRequest::findOrFail($id);

$buildings = $imageRequest->buildingImages;

foreach ($buildings as $building) 
    dd($building->type);

我收到此错误:

SQLSTATE[42S22]:未找到列:1054 未知列 “where 子句”中的“building_types.building_image_id”(SQL:选择 * 来自building_types 其中building_types.building_image_id = 45 并且building_types.building_image_id 不为空限制 1)

我在这里做错了什么?

【问题讨论】:

【参考方案1】:

这是因为默认情况下,laravel 会查找一个名为 model_id 的主键,并且鉴于您使用的是不同的列名 (source),因此您需要在定义关系时指定:

作为文档states:

Eloquent 根据模型名称确定关系的外键。在这种情况下,Phone 模型被自动假定为具有user_id 外键。如果您希望覆盖此约定,您可以将第二个参数传递给 hasOne 方法:

return $this->hasOne('App\Phone', 'foreign_key');

此外,Eloquent 假设外键的值应该与父列的 id(或自定义的 $primaryKey)相匹配。也就是说,Eloquent 会在Phone 记录的user_id 列中查找用户id 列的值。如果您希望关系使用 id 以外的值,您可以将第三个参数传递给 hasOne 方法,指定您的自定义键:

return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

现在这很清楚了。让我们谈谈关系本身。

您正在定义一个BuildImage 有一个BuildingType。但是按照这种逻辑,外键应该存储在building_types 表中,而不是相反(source 列出现在building_images 表中)。而且-我只是假设-许多BuildImage 可以属于特定的BuildingType。所以,如果这个假设是正确的:

BuildImage 属于特定的BuildingTypeBuildinType 可以在多个BuildImages 中指定

所以,你应该这样定义你的关系:

BuildImage.php

public function type()

    return $this->belongsTo('App\BuildingType', 'source');

BuildingType.php

public function images()

    return $this->hasMany(BuildingImage::class, 'source');

【讨论】:

所以我必须在你的代码示例中的“foreign_key”中填写“source”? @Michael 我会更新的。但我认为你应该对你们的关系有所不同。 您也可以使用类代替字符串,有些人(包括我自己)倾向于使用字符串。 return $this->hasOne(App\Phone::class, 'foreign_key', 'local_key'); @JohnHalsey 是的,确实如此。很好的观察,我会把它包括在内。【参考方案2】:

您是否尝试过这样表示索引 ID?

public function buildingImage()

    return $this->belongsTo('App\BuildingImage', 'image_request_id');

Eloquent 根据 型号名称。在这种情况下,电话模型被自动假定为 有一个 user_id 外键。如果您希望覆盖此约定, 您可以将第二个参数传递给 hasOne 方法:

return $this->hasOne('App\Phone', 'foreign_key');

https://laravel.com/docs/5.7/eloquent-relationships#one-to-one

【讨论】:

【参考方案3】:

你的 BuildImage 模型应该是

/** * 获取建筑物图像的来源类型。 */

public function type() 
    return $this->hasOne('App\BuildingType',"id","source"); 

而 BuildingType 模型应该是

/** * 获取拥有该建筑类型的建筑图像。 */

public function buildingImage()

    return $this->belongsTo('App\BuildingImage',"source","id");

这应该可行。 欲了解更多信息,请查看 https://laravel.com/docs/5.7/eloquent-relationships#one-to-one

【讨论】:

以上是关于Laravel 5.6 OneToOne 关系不起作用的主要内容,如果未能解决你的问题,请参考以下文章

barryvdh/laravel-cors 配置在 Laravel 5.6 中不起作用;忽略'allowedMethods'

Laravel 5.6 护照 API 身份验证在获取请求中不起作用

将 Laravel 从 5.6 升级到 6.0 后,调用未定义的 str_random() 函数不起作用

Laravel 5.6 API 资源未显示关系数据

Laravel 5.6 |雄辩的一对多关系

Laravel 5.6 Passport 驱动程序在 socket.io 中不起作用并给出未经授权的异常