Hibernate Tutorial
Core Hibernate
Hibernate Mapping
Hibernate Annotations
Hibernate with Spring Framework
Hibernate with Database
Hibernate Log4j
Inheritance Mapping
In Hibernate, the term "bag" usually refers to a collection that can contain duplicate elements and does not guarantee any specific order (similar to a java.util.List
). In the context of ORM (Object-Relational Mapping), this means mapping a one-to-many or many-to-many association to a collection of this nature.
In this tutorial, we'll discuss how to use bag mapping in Hibernate.
pom.xml
.hibernate.cfg.xml
configuration file.Let's say we have two entities: Author
and Book
. An author can write multiple books, but each book has only one author. Here, the collection of books for an author is a bag, as an author might write multiple editions of the same book title.
@Entity @Table(name="author") public class Author { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name="author_id") private List<Book> books = new ArrayList<>(); // Constructors, getters, setters, etc. }
@Entity @Table(name="book") public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String title; // No need to define the Author relationship here for this example. // Constructors, getters, setters, etc. }
To save an author with a couple of books:
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Author author = new Author(); author.setName("George Orwell"); Book book1 = new Book(); book1.setTitle("1984"); Book book2 = new Book(); book2.setTitle("1984"); // Intentional duplicate for demonstration. author.getBooks().add(book1); author.getBooks().add(book2); session.persist(author); tx.commit(); session.close();
Here, you can see that we intentionally added two books with the same title "1984" to demonstrate that bags can hold duplicate elements.
Performance Issues: Hibernate might need to recreate the entire bag (delete all and re-insert) even if you make a minor change to the collection. This is because Hibernate might not be able to figure out which specific elements have been added or removed from the bag.
No Order: Bags don't maintain any order, so if your application has a requirement to fetch elements in a specific order, then bags might not be the best choice.
Semantic Ambiguity: It's not always clear when you would use a bag over a set or list, as a bag is less semantically clear. It's a collection that allows duplicates like a list but doesn't guarantee order.
In many situations, a Set
(which does not allow duplicates) or a List
(which maintains order) may be a more appropriate choice than a bag. However, understanding the concept and usage of bag mapping can be beneficial in specific scenarios where neither order nor uniqueness is crucial.
Hibernate bag mapping example:
In Hibernate, a bag represents an unordered collection of elements, typically used for mapping Java collections like List
or Set
to database tables.
@Entity @Table(name = "orders") public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "order_id") private Long id; @ElementCollection @CollectionTable(name = "order_items", joinColumns = @JoinColumn(name = "order_id")) @Column(name = "item") private List<String> items; // Other properties and methods }
Bag mapping in Hibernate XML:
The equivalent XML mapping for bag mapping in Hibernate would look like this:
<class name="Order" table="orders"> <id name="id" type="long"> <generator class="identity"/> </id> <bag name="items" table="order_items"> <key column="order_id"/> <element column="item" type="string"/> </bag> </class>
Mapping bag collections in Hibernate:
Bag collections are mapped using @ElementCollection
and @CollectionTable
annotations.
@Entity @Table(name = "orders") public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "order_id") private Long id; @ElementCollection @CollectionTable(name = "order_items", joinColumns = @JoinColumn(name = "order_id")) @Column(name = "item") private List<String> items; // Other properties and methods }
Hibernate bag mapping cascade options:
Cascade options determine how changes to the bag collection should propagate to associated entities.
@Entity @Table(name = "orders") public class Order { // ... @ElementCollection @CollectionTable(name = "order_items", joinColumns = @JoinColumn(name = "order_id")) @Column(name = "item") @Cascade(value = org.hibernate.annotations.CascadeType.ALL) private List<String> items; // ... }
Inverse attribute in Hibernate bag mapping:
The inverse
attribute in Hibernate indicates whether the bag is responsible for managing the association.
@Entity @Table(name = "orders") public class Order { // ... @ElementCollection @CollectionTable(name = "order_items", joinColumns = @JoinColumn(name = "order_id")) @Column(name = "item") @InverseJoinColumns(@JoinColumn(name = "item_id")) private List<String> items; // ... }
Lazy loading with Hibernate bag mapping:
Lazy loading ensures that the bag collection is loaded from the database only when accessed.
@Entity @Table(name = "orders") public class Order { // ... @ElementCollection @CollectionTable(name = "order_items", joinColumns = @JoinColumn(name = "order_id")) @Column(name = "item") @LazyCollection(LazyCollectionOption.TRUE) private List<String> items; // ... }
Bidirectional association with bag mapping in Hibernate:
Bidirectional associations involve two entities having references to each other.
@Entity @Table(name = "orders") public class Order { // ... @OneToMany(mappedBy = "order") @LazyCollection(LazyCollectionOption.TRUE) private List<OrderItem> orderItems; // ... } @Entity @Table(name = "order_items") public class OrderItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "item_id") private Long id; @ManyToOne @JoinColumn(name = "order_id") private Order order; // Other properties and methods }
Indexed bag mapping in Hibernate:
Indexed bags allow accessing elements by index, similar to a List
with an ordered index.
@Entity @Table(name = "orders") public class Order { // ... @ElementCollection @CollectionTable(name = "order_items", joinColumns = @JoinColumn(name = "order_id")) @Column(name = "item") @OrderColumn(name = "item_index") private List<String> items; // ... }