Как правильно создать связи в сущностях

Сущность описывающая машину

@Entity
@Table(name = "machine")
public class Machine {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    // Список узлов машины
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "machine_node", joinColumns = @JoinColumn(name = "machine_id"), inverseJoinColumns = @JoinColumn(name = "node_id"))
    private List<NodeMachine> nodeMachines = new ArrayList<>();
}

Сущность описывающая деталь/узел

@Entity
@Table(name = "node_machine")
public class NodeMachine {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

На каждой машине установлено несколько деталей (список nodeMachines), и каждая деталь может быть установлена на разные машины, поэтому добавил ManyToMany.

Каждая деталь установлена на конкретной машине в определенном кол-ве. Я хочу получить количество узлов установленных в конкретной машине, зная имя узла и машины.

Опишу более подробно, что находится в таблицах. Сразу скажу, что пример не очень удачный, просто для понимания. В таблице Machine у нас есть 100 мотоциклов M (1-100) и 100 автомобилей C (1-100). А в таблице NodeMachine всего одна запись - колесо K1, которое подходит на все сто мотоциклов и на все сто машин. Из этого никак не определить сколько колес должно быть у каждого мотоцикла и у каждой машины. Поэтому я считаю, что должна быть третья таблица где каждой машине и мотоциклы указано количество колес. А держать в таблице 200 записей колес для мотоциклов и 400 записей для машин я считаю, что это слишком избыточно.

Для этого придется создать еще одну таблицу count_machine_node с полями

- machine_id
- node_id
- count

Но какие связи необходимо прописать в этих сущностях?

Как правильно связать эти три таблицы?

Я так понимаю, что аннотация ManyToMany создаст третю таблицу связи двух таблиц по ключам machine_id и node_id. Но как указать, чтобы в этой таблице было создано поле count? Или hibernate так не умеет делать и все-таки придется создавать третью сущность для этого? Например вот тут Hibernate – Many-to-Many example – join table + extra column похожая задача решаться с помощью третьей сущности. Правда статья очень старая, может уже есть решение по проще?


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

Автор решения: ArchDemon

Я вам предлагаю следующий вариант решения. От таблицы "машины" мы отказываемся совсем. У нас будет таблица узлов (Node) и их наследников (ChildNode). Для понимания какого типа у нас узел вводится таблица типов узлов - Type. Она будет принимать значения: машина, свеча, колесо и т.д.

Тут нет связей Многие-ко-Многим. Только Один-ко-Многим (Многие-к-Одному).

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

Схема

UPD

Если нам нужно найти все узлы входящие в машину, то в случае плоского справочника (когда у нас есть машина и все дочерние узлы цепляются только к ней), необходимо из таблицы ChildNode выбрать все записи с idParentNode выбранной машины. Если нам нужно знать только типы этих узлов, то в запросе можно сделать группировку по типу узла (ChildNode JOIN Node (idNode -> id) GROUP BY Node.idType), ну или же DISTINCT по типу узла.

Если у нас справочник иерархический, то будет сложнее. Придётся рекурсивно выбирать из всех узлов все дочерние узлы.

Как это работает на примере колёс (таблица Node):

  • узел № 1 "Камаз" типа "машина"
  • узел № 2 "Мотоцикл" типа "машина"
  • узел № 3 "колесо на Камаз" типа "колесо"
  • узел № 4 "комплект колес на Камаз" типа "колесо"
  • узел № 5 "колесо на мотоцикл" типа "колесо"

Вы создаёте для узла № 1 дочерние (таблица ChildNode):

  • № 3 в количестве 6
  • № 4 в количестве 1

Вы создаёте для узла № 2 дочерние (таблица ChildNode):

  • № 5 в количестве 2
→ Ссылка