Полиморфизм гибернации
Это вопрос полиморфизма Гибнера и дизайн модели данных
вопрос; они переплетены. Я использовал Hibernate в прошлом,
и наслаждались им, но иногда мне трудно думать
ничего, кроме тривиальных конструкций. Не стук в спящий режим; просто
что ОРМ вообще может быть сложным.
Я думаю, что это вопрос Hibernate 101, но я не уверен. То, что я пытаюсь достичь, возможно даже не возможно.
У меня есть абстрактный класс Fruit, который будет подклассифицирован в Apple
и оранжевый. У меня есть класс Note, который представляет заметки или комментарии
о яблоках и апельсинах. Apple или Orange могут иметь много Notes
связанных с ним, но только один Apple или Orange когда-либо будут
связанные с данным примечанием.
Вот эскизы классов, где я пока что не указываю, где
объект id go и свойства яблок, которые различают
их из Апельсинов. В настоящее время я не чувствую решимости о том, какую стратегию наследования Hibernate я использую.
abstract public class Fruit {
}
// Apples have notes written about them:
public class Apple extends Fruit {
private Set<Note> note;
...
@OneToMany(cascade = CascadeType.ALL)
public Set<Note> getNote() {
return note;
}
}
// Oranges have notes written about them:
public class Orange extends Fruit {
private Set<Note> note;
...
@OneToMany(cascade = CascadeType.ALL)
public Set<Note> getNote() {
return note;
}
}
Ниже приведен класс Note, в котором мы видим, что
он имеет поля для Apple и Orange. Недостаток или неэффективность
в этом проекте заключается в том, что экземпляр одной заметки будет указывать только на
один из Apple или Orange, и оба они оба. Поэтому, если примечание привязано к
Apple, оранжевое поле является излишним и неприглядным, и
семафоре.
// A note about an Apple or Orange
public class Note {
private String theNote;
private Apple apple;
private Orange orange;
...
// with the usual many to one mapping
@ManyToOne
@JoinColumn(name = "apple_id")
public Apple getApple() {
return apple;
}
// with the usual many to one mapping
@ManyToOne
@JoinColumn(name = "orange_id")
public Orange getOrange() {
return orange;
}
...
}
Тем не менее, это класс Note, который, как мне кажется, я хочу основать
дизайн, но я не уверен, как думать об этом с уважением
для аннотации Hibernate и отображения таблицы:
// A note about a fruit:
public class Note {
private String theNote;
private Fruit fruit;
...
}
после чего фрукты будут либо экземпляром Apple, либо апельсином.
Может ли этот последний класс Note со ссылкой на Fruit, который фактически будет содержать Apple или Orange, даже примирится с Hibernate ORM mapping? Если да, может кто-нибудь, пожалуйста, поговорите о том, как.
Ответы
Ответ 1
Это абсолютно возможно. Вы можете связать заметки с абстрактным классом Fruit
вместо того, чтобы повторять их в каждой из реализаций:
@Entity
@Inheritance
public abstract class Fruit {
private Set<Note> notes;
...
@OneToMany(cascade = CascadeType.ALL, mappedBy = "fruit")
public Set<Note> getNotes() {
return notes;
}
}
@Entity
public class Apple extends Fruit {
...
}
@Entity
public class Orange extends Fruit {
...
}
@Entity
public class Note {
private String theNote;
@ManyToOne
private Fruit fruit;
...
}
Ét voilà!
- добавление на основе комментария:
JPA предоставляет множество стратегий для работы с наследованием. соответствующий раздел в учебнике по Java EE должен помочь вам начать работу.
В основном, ваши варианты:
- Сохранение всего в одной таблице и использование столбца дискриминатора, чтобы узнать, какая строка является типом
- Сохранение каждого конкретного класса (Apple и Orange) в отдельной таблице
- Наличие общей таблицы фруктов со столбцом дискриминатора, а таблицы Apple и Orange с внешним ключом в таблице Fruit.
Другое редактирование:
Заметил, что это спящий режим, а не вопрос JPA. Однако не имеет особого значения, поскольку параметры одинаковы. Здесь соответствующий раздел в документах Hibernate.
Ответ 2
Этот шаблон очень распространен в базе данных на базе Hibernate. Как это работает внутри, в значительной степени зависит от того, какая стратегия наследования используется.
При использовании таблицы для каждого класса или таблицы для наследования подкласса будет создана таблица для каждого подкласса/класса. Например, в вашем случае у вас будет таблица Fruit и две таблицы Apple
и Orange
, с ссылками на внешние ключи между Fruit и Apple/Orange. При запросе одного фрукта (будь то яблоко или апельсин) по ID, Hibernate будет нарушать соединение с таблицей Fruit с таблицей Apple и Orange. Каждая строка будет преобразована в Apple или Orange, в зависимости от того, из какой таблицы были получены поля.
Другая возможность - использовать дискриминаторы. Будет использоваться одна таблица Fruit
, которая будет содержать поле дискриминатора (например, fruit_type
, принимающее значения Apple
и Orange
). В зависимости от значения этого поля Hibernate определит, является ли соответствующий объект Apple или Orange.
В вашем случае, в случае активной загрузки, когда Hibernate загружает объект Note, он с нетерпением будет получать соответствующий Fruit и заполнять поле фруктов экземпляром Apple или Orange соответственно.
В случае ленивой выборки поле фруктов будет прокси-сервером, реализующим интерфейс Fruit. Пока не загрузится фактическое поле плодов, его тип не определен.
Надеюсь, что это ответит на некоторые ваши запросы.