Преобразовать связь сущностей ManyToMany в ManyToOne

У меня есть три таблицы, Блюдо,Информация о Блюде и Категория,которые созданы в базе следующим образом:

dishes

CREATE TABLE restaurant_schema.dishes
(
    id           BIGINT AUTO_INCREMENT PRIMARY KEY,
    name         VARCHAR(64)   NOT NULL,
    price        NUMERIC(7, 2) NOT NULL,
    dish_info_id BIGINT        NOT NULL UNIQUE REFERENCES restaurant_schema.dish_info
);

dish_info

CREATE TABLE restaurant_schema.dish_info
(
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    category_id BIGINT REFERENCES restaurant_schema.categories (id),
    weight      INT NOT NULL,
    recipe_id   BIGINT REFERENCES warehouse_schema.recipes (id)
);

categories

CREATE TABLE restaurant_schema.categories
(
    id   BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(128)
);

Мне не нравится структура связей, с одной стороны мне кажется не до конца логичным что в категории(categories) хранится информация о блюде(dish_info), а не само блюдо(dish).
Также я бы хотел видеть связь между блюдом и категорией в виде ManyToOne, а не ManyToMany, поэтому я думаю создать промежуточную сущность, но проблема в том что в результате получится что в этой сущности будут хранится просто два ключа, что тоже мне кажется не до конца логичным.

Пока что моя объектная модель выглядит следующим образом:

Dish

public class Dish {

    @Id
    @Column(name = "id")
    Long id;

    @Column(name = "name")
    String name;

    @Column(name = "price")
    BigDecimal price;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "dish_info_id")
    DishInfo dishInfo;
}

DishInfo

public class DishInfo {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @Column(name = "weight")
    Integer weight;

    @OneToMany
    @JoinColumn(name = "category_id")
    List<Category> categories;

    @OneToOne
    @JoinColumn(name = "recipe_id")
    Recipe recipe;
}

Category

public class Category {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @Column(name = "name")
    String name;
}

Как в моем случает можно улучшить объектную и реляционную модель?
Как бы вы организовали связи?

Буду благодарен любому совету


Ответы (1 шт):

Автор решения: Михаил Ребров

Вы говорите:

@Smetana Po Aktsii:
хотел видеть связь между блюдом и категорией в виде ManyToOne, а не ManyToMany

, во избежание чего хотите

@Smetana Po Aktsii:
создать промежуточную сущность, ... в которой будут хранится просто два ключа

Смею заметить, что создавая промежуточную сущность с двумя ключами Вы по факту создаете ничто иное как связь MANY_TO_MANY, просто вы её оборачиваете сущностью... в остальном же она будет играть ту же самую роль что и таблица, создаваемая при определении данной связи, которая просто хранит два ключа.

Тут вам стоит самому подумать, понять и решить:
может быть отношение к MANY_TO_MANY было предвзятым и желание избавиться от него любой ценой просто заблуждение?

Также хочу отметить что чисто функционально MANY_TO_MANY и ONE_TO_MANY отличаются.
И данные связи имеют совершенно разные возможности.
И тут стоит отталкиваться не столько от желаний, сколько от реальных потребностей.

  • Может ли у Вас одно и то же блюдо одновременно находиться в двух разных категориях?
  • В будущем такое Вы тоже не планируете?

Если так то делайте ONE_TO_MANY.
В противном случае придется делать MANY_TO_MANY.

Также хочу отметить следующее:
на данный момент таблица restaurant_schema.dish_info НЕ СООТВЕТСТВУЕТ классу DishInfo.
В таблице у Вас MANY_TO_ONE, а в классе ONE_TO_MANY...
Это ошибка ... с такой таблицей в классе у вас должно быть

@ManyToOne
Category сategory;

Также я присоединюсь к комментарию @Alex Krass о том, что на данный момент не вижу необходимости в разделении Dish и DishInfo на два класса.
Возможно, Вы нам не все рассказали, но из того что мы видим - необходимости в данном разделении нет.
Я искренне надеюсь, что это не я Вас подтолкнул к действиям.
Больше сущностей не всегда значит лучше, и в том же ответе в другом кейсе я наоборот старался перенести поле в существующий класс, вместо того чтобы создавать ненужную сущность.
С опытом у Вас получится лучше чувствовать такие моменты:
пока же просто держите в голове, что для создания новой сущности нужно очень хорошо понимать для чего именно Вы это делаете.
Если Вы не можете уверенно ответить на этот вопрос, то стоит задуматься...

→ Ссылка