Что такое Embeddable в JPA?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
@Embeddable в JPA/Hibernate
@Embeddable — это аннотация JPA, которая позволяет создавать несамостоятельные объекты (Value Objects), которые встраиваются в сущности. Это мощный инструмент для организации кода и работы с комплексными типами данных, соответствуя DDD принципам.
Основная концепция
Embeddable объект — это класс, который:
- НЕ имеет своего первичного ключа (id)
- НЕ может существовать самостоятельно в БД
- Всегда встроен в какую-то сущность
- Находится в одной строке с сущностью
@Embeddable
public class Address {
@Column(name = "street")
private String street;
@Column(name = "city")
private String city;
@Column(name = "country")
private String country;
@Column(name = "postal_code")
private String postalCode;
}
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
@Column(name = "name")
private String name;
@Embedded
private Address billingAddress;
@Embedded
private Address shippingAddress;
}
В какой таблице хранятся данные
Address НЕ создает отдельную таблицу! Его поля встраиваются прямо в таблицу customer.
Сравнение подходов
| Подход | Таблицы | Преимущества | Недостатки |
|---|---|---|---|
| @Embeddable | 1 таблица | Простота, производительность | Нельзя reuse |
| @Entity | 2 таблицы | Гибкость, reuse | JOINы, N+1 |
Примеры использования Embeddable
1. Value Object - Деньги
@Embeddable
public class Money {
@Column(name = "amount", precision = 19, scale = 2)
private BigDecimal amount;
@Column(name = "currency")
private String currency;
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new IllegalArgumentException("Currencies don't match");
}
return new Money(this.amount.add(other.amount), this.currency);
}
}
@Entity
public class Order {
@Id
private UUID id;
@Embedded
private Money totalPrice;
@Embedded
private Money discountAmount;
}
2. Value Object - Координаты
@Embeddable
public class GeoLocation {
@Column(name = "latitude")
private Double latitude;
@Column(name = "longitude")
private Double longitude;
public double distanceTo(GeoLocation other) {
return calculateDistance(this, other);
}
}
@Entity
public class Store {
@Id
private UUID id;
@Embedded
private GeoLocation location;
}
3. Value Object - Диапазон дат
@Embeddable
public class DateRange {
@Column(name = "start_date")
private LocalDateTime startDate;
@Column(name = "end_date")
private LocalDateTime endDate;
public boolean contains(LocalDateTime date) {
return !date.isBefore(startDate) && !date.isAfter(endDate);
}
}
@Entity
public class Promotion {
@Id
private UUID id;
@Embedded
private DateRange validPeriod;
}
@AttributeOverride для множественного использования
Когда нужно использовать Embeddable несколько раз:
@Entity
public class Company {
@Id
private UUID id;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "street", column = @Column(name = "hq_street")),
@AttributeOverride(name = "city", column = @Column(name = "hq_city"))
})
private Address headquartersAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "street", column = @Column(name = "ops_street")),
@AttributeOverride(name = "city", column = @Column(name = "ops_city"))
})
private Address operationalAddress;
}
Преимущества @Embeddable
- DDD Compliance - Value Objects как в Domain-Driven Design
- Инкапсуляция - логика работы находится внутри класса
- Переиспользование - можно использовать в разных сущностях
- Типобезопасность - вместо строк используются объекты
- Тестируемость - легко тестировать логику Value Object отдельно
- Производительность - нет дополнительных JOINов (все в одной таблице)
Ограничения @Embeddable
- НЕ может содержать коллекции (@OneToMany, @ManyToMany)
- НЕ может иметь отношения к другим сущностям
- НЕ может быть переиспользован как отдельная сущность в других случаях
Заключение
@Embeddable — это мощный инструмент для создания чистой архитектуры, соответствующей принципам DDD. Это позволяет encapsulate бизнес-логику в Value Objects, делая код более читаемым и тестируемым, при этом сохраняя производительность.