如何创建一个表与其他两个表具有多对一关系的关系

时间:2020-02-26 19:34:54

标签: laravel eloquent eloquent-relationship

我在Eloquent中使用Laravel。在我的示例中,我有3个表:image,user和post。我要实现的是图像可以完全属于一个用户和/或完全属于一个帖子。

所以我认为表格应该是这样的:

Image
------------
id
image_name

user
------------
id
name
image_id

post
------------
id
text
image_id

我尝试使用以下关系:

  • 图片:belongsTo->用户
  • 图片:belongsTo->发布
  • 用户:hasOne->图片
  • 发布:hasOne->图片

但是当我执行$user->image()->save(someImageObject);时,我得到一个错误,即user_id表上的列image是未知的,这是正确的。所以我以为我可能误解了这种关系,需要翻转它们,所以我将模型上的关系(即使现在感觉不对)更改为:

  • 图片:hasOne->用户
  • 图片:hasOne->发布
  • 用户:belongsTo->图片
  • 帖子:belongsTo->图片

当我执行$user->image()->save(someImageObject);时,出现错误,提示无法在save()关系上调用BelongsTo。当我创建这样的关系时:$image->user()->save(theUserObject);可以正常工作,但是在代码中感觉/看起来很奇怪,因为我想向用户而非用户添加图像。

这是简单的方法吗,我的“感觉很奇怪”感觉不对吗?还是有其他方法可以定义我的关系?

我还尝试了变体关系(多对多),这似乎很好,但是我不能限制用户/帖子只有一个图像。变体一对多关系听起来确实像我需要的名字,但我不知道这应该如何工作,因为它在图像表上具有关系id /类型。当我使用这种关系类型进行测试时,当我尝试将图像链接到用户并发布时,它会替换图像表上的类型(如我实际期望的那样)

2 个答案:

答案 0 :(得分:2)

您不清楚这些对象之间的关系。但是基于此:

用户:hasOne->图片
帖子:hasOne->图片

我假设每个用户或每个帖子只能有一张图片。


建立这些关系时,期望“子”对象将保留其表中的“父” ID。当“父代”可以是两个不同模型之一时,情况就更复杂了;这被称为多态关系。 Laravel的documentation on polymorphic relations专门针对您的情况

一对一多态关系类似于简单的一对一关系;但是,目标模型可以在单个关联上属于一种以上类型的模型。例如,博客PostUser可以共享与Image模型的多态关系。使用一对一的多态关系可以使您拥有用于博客文章和用户帐户的唯一图像的单个列表。

因此您的数据库应该看起来像这样,孩子可以跟踪父母的ID。

posts
-----
id
text

users
-----
id
name

images
------
id
image_name
imageable_id
imageable_type

然后按如下方式定义您的关系:

<?php
class Image extends Model
{
    public function imageable() {
        return $this->morphTo();
    }
}

class Post extends Model
{
    public function image() {
        return $this->morphOne('App\Image', 'imageable');
    }
}

class User extends Model
{
    public function image() {
        return $this->morphOne('App\Image', 'imageable');
    }
}

现在,获取用户图像就像获取image属性一样简单。要找出图像的所有者,请查看imageable属性。您可以使用多种方法查看所有者是什么:

$user = User::find($id);
$image = $user->image;

$image = Image::find($id);
$owner = $image->imageable;
if ($owner instanceof App\User) {
    // do stuff
} else {
    // do other stuff
}

要通过正确的数据库设置来更新关系,很简单:

$user->image()->save($image);
$post->image()->save($image);
$image->imageable()->save($user);

答案 1 :(得分:1)

您的问题出在您的数据模型中。

我发现这里用英语陈述我的问题很有帮助,并且通常可以解决数据库对象之间的相互关系。让我们从这个问题开始,然后将其归结为一个语句。

我认为,您的用户将不仅限于在帐户的整个生命周期内放置一张图片。因此,我们希望用户能够添加任意数量的图像。这就是声明;

我希望我的用户具有许多图片

现在,我们可以在 user 表中为用户可以拥有的每个图像提供一列。但是,然后,我们很快就会用完列,并且必须不断更改查询以适应这种情况。这意味着我们需要分别存储图像,以便我们可以拥有尽可能多的图像,因此意味着要包含图像的另一个表。但是我们怎么知道谁拥有图像?

我希望我的图像属于一个用户

从这两个语句中,我们知道用户不受限于他们拥有的图像,并且任何图像都必须属于用户(或帖子,我们稍后再看)。

users
=======
id
name

images
=======
id
name
user_id

我们看到的问题是,这破坏了您对图像可以属于用户或帖子或两者的下一个声明。但是我们可以将其归结为声明;

图像可能属于用户帖子,或者可能是两者

从这里开始,我们需要一种方法来告诉图片“您可能没有用户,也没有帖子”。这是我们在图像表上引入可为空的字段的地方。

users
=======
id
name

posts
=======
id
name

images
=======
id
name
user_id nullable
post_id nullable

现在,您从这里开始询问有关检索此数据的问题。我们了解以下内容:

  • 用户可以拥有许多图像
  • 帖子可以有很多图片
  • 图片可以属于用户,也可以属于帖子

注意我俗气的强调。这向您提示了您可能需要在模型上建立的关系。

class User {
  public function images() {
    return $this->hasMany('Image');
  }
}

class Post {
  public function images() {
    return $this->hasMany('Image');
  }
}

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

  public function post() {
    return $this->belongsTo('Post');
  }
}

希望这有助于清理问题!