@embeddable vs @entity для отображения коллекции
Это должно быть довольно наивно, но я сомневаюсь, когда следует использовать @Entity
и @Embeddable
.
Скажем, у меня есть класс User
и Notification
.
@Entity
public class User{
//other properties
@onetomany
private List<Notification> notifications;
}
@Entity
public class Notification{
//properties
}
Я понимаю, что будут таблицы для классов User
и Notification
, а также третья таблица для сопоставления.
Что делать, если я так делаю?
@Entity
public class User {
//other properties
@ElementCollection
private List<Notification> notifications;
}
@Embeddable
public class Notification{
//properties
}
Я знаю, что это не создаст таблицу для Notification
. Но я все еще могу хранить объекты уведомлений. Я просмотрел документацию, но пару сомнений:
- Это зависит от того, хочу ли я видеть класс B как отдельную таблицу?
- Есть ли разница в производительности, создающая таблицу и встраиваемый объект?
- Что я не могу сделать с встраиваемым объектом, который я могу сделать с таблицей, отличной от прямого запроса таблицы?
ПРИМЕЧАНИЯ
Для тех, кто читает этот вопрос, этот question тоже может вам помочь.
Ответы
Ответ 1
- Это зависит от того, хочу ли я видеть класс B как отдельную таблицу?
Да, когда вы используете @Embedded
, вы вставляете этот объект @Embeddable
в класс @Entity
, что позволяет добавлять столбцы для внедренного объекта в ту же таблицу класса @Entity
.
- Есть ли разница в производительности, создающая таблицу и встраиваемый объект?
Когда вы используете @Embedded
, для создания таблицы требуется один запрос, а также для вставки и выбора строки. Но если вы его не используете, требуется несколько запросов, поэтому использование @Embedded
дает большую производительность, можно сказать.
- Что я не могу сделать с встраиваемым объектом, который я могу сделать с таблицей, отличной от прямого запроса таблицы?
Удаление соответствующего внедренного объекта может быть, но для этого могут быть нарушения ограничений целостности.
Ответ 2
В JPA существует несколько способов создания составных ключевых полей. Давайте посмотрим на метод, используя @Embeddable annotation
.
Давайте начнем с класса Entity.
@Entity
@Table
public class TraceRecord {
@Id
private TraceRecordPk id;
@Version
@Transient
private int version;
@Column(columnDefinition = "char")
private String durationOfCall;
@Column(columnDefinition = "char")
private String digitsDialed;
@Column(columnDefinition = "char")
private String prefixCalled;
@Column(columnDefinition = "char")
private String areaCodeCalled;
@Column(columnDefinition = "char")
private String numberCalled;
}
Это довольно простой класс Entity с полями @Id и @Version и несколькими определениями @Column. Не вдаваясь в подробности, вы увидите, что поле @Version также аннотируется @Transient. Я сделал это просто потому, что в моей таблице также нет столбца для отслеживания версий, но моя база данных ведется журналом, поэтому я не слишком беспокоюсь о версировании. Вы также заметите, что поля @Column имеют значение "char", установленное в атрибуте columnDefinition. Это связано с тем, что поля в моей таблице определены как char, а не varchar. Если бы они были varchar, мне не нужно было бы это делать, поскольку по умолчанию String сопоставляет поля varchar.
Поле @Id
- это то, что Im заинтересовало прямо сейчас. Это не стандартный Java-тип, а класс Ive. Вот этот класс.
@Embeddable
public class TraceRecordPk implements Serializable {
private static final long serialVersionUID = 1L;
@Temporal(TemporalType.DATE)
@Column
private Date dateOfCall;
@Column(columnDefinition="char")
private String timeOfCall;
@Column(columnDefinition="char")
private String callingParty;
/**
* Constructor that takes values for all 3 members.
*
* @param dateOfCall Date the call was made
* @param timeOfCall Time the call was made
* @param callingParty Extension from which the call originated
*/
public TraceRecordPk(Date dateOfCall, String timeOfCall, String callingParty) {
this.dateOfCall = dateOfCall;
this.timeOfCall = timeOfCall;
this.callingParty = callingParty;
}
}
Чтобы этот класс мог быть полем @Id в классе Entity, его необходимо аннотировать с помощью @Embeddable, как я упоминал ранее. 3 поля Ive, выбранные для моего составного ключа, являются обычными определениями @Column. Вместо того, чтобы создавать геттеры/сеттеры для каждого поля, Ive просто реализовал конструктор, который принимает значения для всех трех полей, делая любой экземпляр неизменным. При аннотировании класса с помощью @Embeddable этому классу потребуется реализовать Serializable. Итак, Ive добавила по умолчанию serialVersionUID для размещения.
Теперь, когда у вас есть класс, созданный и аннотированный с помощью @Embeddable
, теперь вы можете использовать его как тип поля @Id в своем классе Entity. Простой материал.