Embeddables and element collections

Hibernate · lesson 18 of 32 · 4 min read

Model things with no identity of their own without inventing an entity, an id and a join.

Open this lesson in the learning hub

Key points

  • An @Embeddable has no id and no lifecycle. Its columns sit in the owner table, so reading it costs nothing extra.
  • Embedding the same type twice - billing and shipping Address - needs @AttributeOverride to keep the columns apart.
  • @ElementCollection puts a collection of values in a side table the parent owns outright. Still no entity and no id.
  • Element collections are rewritten wholesale: on any change Hibernate deletes every row for that parent and re-inserts. Keep them small.
  • The moment the thing must be queried alone, referenced by another entity or versioned, it has become an @Entity.
  • Give embeddables real equals/hashCode and no setters. They are compared by value, so treat them as value objects.

Example

@Embeddable
public record Address(String street, String city, String postcode) { }

@Entity
public class Customer {

    @Id @GeneratedValue private Long id;

    @Embedded                                    // street, city, postcode
    private Address billing;                     // columns on the customer table

    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "street",   column = @Column(name = "ship_street")),
        @AttributeOverride(name = "city",     column = @Column(name = "ship_city")),
        @AttributeOverride(name = "postcode", column = @Column(name = "ship_postcode"))
    })
    private Address shipping;

    @ElementCollection                           // side table: customer_tags
    @CollectionTable(name = "customer_tags", joinColumns = @JoinColumn(name = "customer_id"))
    @Column(name = "tag")
    private Set<String> tags = new HashSet<>();
}

// Records work as embeddables in Hibernate 6. They cannot be entities:
// an entity must be non-final, mutable and have a no-arg constructor.

No id of its own means it is a value type, not an entity.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Hibernate course, and every lesson in it is listed on the Hibernate contents page.