After reading my blog post about eager initialization of lazy 1:1 or M:1 associations because of the cascade merge attribute, someone asked about if it applies for 1:M and M:N associations as well? The answer is, yes it applies.
Let’s create another small entity in order to illustrate that case as well.
@Entity @Table(name="T_BAZ") public class Baz { @Id @GeneratedValue private Long id; public Long getId() { return id; } }
Then, we add a 1:M association within Foo entity as follows.
@Entity @Table(name="T_FOO") public class Foo { ... @OneToMany(cascade=CascadeType.MERGE) @JoinColumn(name="foo_id") private Collection<Baz> bazList = new ArrayList<>(); public Collection<Baz> getBazList() { return bazList; } public void setBazList(Collection<Baz> bazList) { this.bazList = bazList; } ... }
As you all know, 1:M and M:N associations are lazy by default, so there is no need for a fetch attribute. Only cascade=CascadeType.MERGE is added.
Foo foo = session.get(Foo.class, 1L); Hibernate: select foo0_.id as id1_21_0_, foo0_.bar_id as bar_id2_21_0_ from T_FOO foo0_ where foo0_.id=?
When we try to access Foo entity via Session.get(), above select query is issued to fetch Foo entity only. A separate select SQL to initialize lazy bazList collections is issued only when we attempt to access its contents.
System.out.println(foo.getBazList().size()); select bazlist0_.foo_id as foo_id2_21_0_, bazlist0_.id as id1_21_0_, bazlist0_.id as id1_21_1_ from T_BAZ bazlist0_ where bazlist0_.foo_id=?
Same story up to this point. However, when we try to merge detached Foo entity, we will see following SQL query is issued, fetching 1:M bazList entries eagerly!
session.merge(foo2); /* load org.speedyframework.persistence.hibernate.test.Foo */ select foo0_.id as id1_22_2_, foo0_.bar_id as bar_id2_22_2_, bar1_.id as id1_20_0_, bazlist2_.foo_id as foo_id2_21_4_, bazlist2_.id as id1_21_4_, bazlist2_.id as id1_21_1_ from T_FOO foo0_ inner join T_BAR bar1_ on foo0_.bar_id=bar1_.id left outer join T_BAZ bazlist2_ on foo0_.id=bazlist2_.foo_id where foo0_.id=?
After playing with Hibernate for about more than a decade, I strongly feel that it is much better and safer to consider ORM in general, Hibernate in particular only as an advanced SQL mapper, nothing more. Quite a few features of ORM tools which look simple, safe and effective in small scale, gets more complicated, may cause side effects, and unexpected problems in a big landscape. Of course, I am not saying Hibernate/ORM is bad, and don’t use it, but what I am saying that don’t expect too much from it, and beware that you might easily shoot yourself on your foot unless you are very careful while employing ORM in your projects.