Как создать отношение, в котором одна таблица имеет отношение «многие к одному» с 2 другими таблицами - PullRequest
0 голосов
/ 26 февраля 2020

Я использую Laravel с Eloquent. В моем примере у меня есть 3 таблицы: изображение, пользователь и сообщение. Чего я хочу добиться, так это чтобы изображение могло принадлежать только одному пользователю и / или одному посту.

Так что я думаю, что таблицы должны быть такими:

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

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

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

Я попытался использовать следующие отношения:

  • image: serveTo -> user
  • image: ownTo -> post
  • пользователь: hasOne -> image
  • post: hasOne -> image

Но когда я делаю $user->image()->save(someImageObject); я получаю сообщение об ошибке, что столбец user_id неизвестен в таблице image, что является правильным. Поэтому я подумал, что, возможно, неправильно понял отношения и мне нужно перевернуть их, поэтому я изменил отношения (даже если сейчас это кажется неправильным) на моделях:

  • image: hasOne -> user
  • image: hasOne -> post
  • user: assignTo -> image
  • post: ownTo -> image

Когда я делаю $user->image()->save(someImageObject); , я получаю сообщение об ошибке, что невозможно save() на BelongsTo отношение. Когда я создаю такое отношение: $image->user()->save(theUserObject);, оно работает нормально, но в коде это выглядит / выглядит странно, поскольку я хочу добавить изображение для пользователя, а не пользователя к изображению.

Так это просто путь к go и мое чувство "это странно" не так? или есть другой способ определить мои отношения?

Я также экспериментировал с морфологическими отношениями (многие ко многим), и это, кажется, работает нормально, но я не могу ограничить то, что пользователь / публикация имеет только одно изображение , Отношения «морфинг один-ко-многим» звучат по имени, как будто это именно то, что мне нужно, но я понятия не имею, как это должно работать, поскольку оно имеет отношение id / type в таблице изображений. Когда я проверяю этот тип отношения, он заменяет тип в таблице изображений, когда я пытаюсь связать изображение с пользователем и публикацией (как я и ожидал)

Ответы [ 2 ]

2 голосов
/ 27 февраля 2020

Ваш вопрос неясен относительно отношений между этими объектами. Но исходя из этого:

пользователь: hasOne -> изображение post: hasOne -> image

Я предполагаю, что у каждого пользователя или записи может быть только одно изображение.


При построении этих отношений ожидается, что «дочерний» объект будет удерживать «родительский» идентификатор в своей таблице. Это сложнее, когда «родитель» может быть одной из двух разных моделей; это известно как полиморфное отношение c. Laravel документация по полиморфам c отношений конкретно относится к вашему сценарию

отношение один к одному полиморф c похоже на простое одно- отношение один к одному; однако целевая модель может принадлежать более чем одному типу модели в одной ассоциации. Например, у блога Post и User может быть отношение polymorphi c к модели Image. Использование отношения «один к одному» polymorphi c позволяет вам иметь единый список уникальных изображений, которые используются как для сообщений в блоге, так и для учетных записей пользователей.

Таким образом, ваша база данных должна выглядеть следующим образом, с ребенком, отслеживающим идентификатор родителя.

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 голос
/ 26 февраля 2020

Ваша проблема здесь заключается в вашей модели данных.

Я считаю, что здесь полезно изложить мою проблему в Engli sh, и это часто может решить, как объекты базы данных связаны друг с другом. Давайте начнем с этой проблемы и сведем ее к утверждению.

Ваши пользователи, я полагаю, не ограничатся размещением одного изображения в течение всего срока действия своей учетной записи. Поэтому мы хотим, чтобы пользователи могли добавлять столько изображений, сколько им нравится. Это становится утверждением:

Я хочу, чтобы мои пользователи имели много изображений .

Теперь мы могли бы получить столбец в таблице 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');
  }
}

Надеюсь, это поможет прояснить ситуацию!

...