← Назад к вопросам

Что такое Embeddable в JPA?

2.0 Middle🔥 141 комментариев
#SOLID и паттерны проектирования#Spring Boot и Spring Data

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

@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.

Сравнение подходов

ПодходТаблицыПреимуществаНедостатки
@Embeddable1 таблицаПростота, производительностьНельзя reuse
@Entity2 таблицыГибкость, reuseJOINы, 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

  1. DDD Compliance - Value Objects как в Domain-Driven Design
  2. Инкапсуляция - логика работы находится внутри класса
  3. Переиспользование - можно использовать в разных сущностях
  4. Типобезопасность - вместо строк используются объекты
  5. Тестируемость - легко тестировать логику Value Object отдельно
  6. Производительность - нет дополнительных JOINов (все в одной таблице)

Ограничения @Embeddable

  • НЕ может содержать коллекции (@OneToMany, @ManyToMany)
  • НЕ может иметь отношения к другим сущностям
  • НЕ может быть переиспользован как отдельная сущность в других случаях

Заключение

@Embeddable — это мощный инструмент для создания чистой архитектуры, соответствующей принципам DDD. Это позволяет encapsulate бизнес-логику в Value Objects, делая код более читаемым и тестируемым, при этом сохраняя производительность.