Как правильно создать связи в сущностях
Сущность описывающая машину
@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 шт):
Я вам предлагаю следующий вариант решения. От таблицы "машины" мы отказываемся совсем. У нас будет таблица узлов (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
