Hibernate Associations and Collections
Collection Mapping in Hibernate
Learn how to map lists, sets, maps, bags, value collections, and entity relationships using Hibernate and JPA.
Collection Types Supported by Hibernate
A persistent class can contain a collection of values or entity references. Common Java collection types are:
ListSetSortedSetMapSortedMapCollection
Hibernate also supports custom collection semantics through its extension points. Prefer standard Java collections and JPA annotations for application code.
public class Question {
private Long id;
private String text;
private List<String> answers;
}Mapping a List of Basic Values
Use @ElementCollection when the collection contains values such as strings, numbers, or embeddable value objects rather than entities.
@Entity
public class Question {
@Id
@GeneratedValue
private Long id;
private String text;
@ElementCollection
@CollectionTable(
name = "question_answer",
joinColumns = @JoinColumn(name = "question_id")
)
@OrderColumn(name = "answer_position")
@Column(name = "answer")
private List<String> answers = new ArrayList<>();
}@OrderColumn stores the list position. Without an order column, use a Set when order is not part of the data model.
Mapping a List of Entities
When a collection contains entity objects, use a relationship such as one-to-many or many-to-many. The following bidirectional mapping stores many answers for one question.
@Entity
public class Question {
@Id
@GeneratedValue
private Long id;
@OneToMany(
mappedBy = "question",
cascade = CascadeType.ALL,
orphanRemoval = true
)
@OrderBy("id ASC")
private List<Answer> answers = new ArrayList<>();
}
@Entity
public class Answer {
@Id
@GeneratedValue
private Long id;
private String text;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "question_id", nullable = false)
private Question question;
}mappedBy identifies the owning field on Answer. Keep both sides synchronized in helper methods so the in-memory model and database relationship remain consistent.
Mapping a Collection in an XML Mapping File
Legacy Hibernate mapping files use <list>, <set>, <bag>, or <map> inside a <class> mapping.
<class name="com.example.Question" table="question">
<id name="id" column="id">
<generator class="identity"/>
</id>
<property name="text" column="question_text"/>
<list name="answers" table="question_answer">
<key column="question_id" not-null="true"/>
<index column="answer_position"/>
<element column="answer" type="string"/>
</list>
</class>The <key> stores the foreign key, <index> stores the list position, and <element> stores the basic value. For entity references, replace <element> with <one-to-many> or <many-to-many>.
Understanding the Key Element
The key column is the foreign key in the collection table. It points back to the identifier of the owning entity.
<key column="question_id" not-null="true" on-delete="cascade" />
Important legacy attributes include:
column: foreign-key column name.not-null: prevents collection rows without an owner.on-delete: controls database-level delete behavior where supported.property-ref: references a property other than the owner's primary key.unique: adds a uniqueness constraint when the relationship requires it.
Indexed and Non-Indexed Collections
Indexed
List and Map need an additional value that represents position or key. In XML this is commonly <index> or <index-many-to-many>.
Non-indexed
Set, Bag, and ordinary collections do not use a numeric position. A set relies on equality and hash code behavior to identify unique elements.
@ElementCollection @MapKeyColumn(name = "answer_type") private Map<String, String> answersByType = new HashMap<>();
Collection Element Types
| Mapping | Use it for | Modern annotation |
|---|---|---|
| Basic element | Strings, numbers, dates, and other basic values. | @ElementCollection |
| Component element | Embeddable value objects such as addresses. | @ElementCollection with @Embeddable |
| One-to-many | Many child entities belong to one parent. | @OneToMany |
| Many-to-many | Multiple entities on both sides share a relationship. | @ManyToMany |
LazyInitializationException. Fetch only the data required by the use case.Collection Mapping Best Practices
- Initialize collection fields to an empty collection instead of
null. - Use
Setonly when equality and uniqueness are well defined. - Use
Listwith an explicit order column when position is meaningful. - Use
Mapwhen a stable key makes lookup clearer than scanning a list. - Use cascade and orphan removal only when the child lifecycle truly belongs to the parent.
- Avoid eager collection fetching for large relationships.
- Do not include lazy collections in
equals()orhashCode(). - Use migrations to create collection tables and foreign-key constraints in production.
