Hi everybody,
i simplified a part of our application (using Hibernate 4.1.5) to explain the problem...
We have a class Entity1 containing a lazy collection (ManyToMany) of class Entity2, which itself contains an eager collection (ManyToMany) of class Entity3 (see below). But if we execute the following code (loading Entity1 with id 1 and traversing it)...
Code:
if (entityManager.isOpen()) {
Entity1 entity1 = entityManager.find(Entity1.class, new Long(1));
Set<Entity2> ent2s = entity1.getEntity2s();
Iterator<Entity2> iter = ent2s.iterator();
...
}
...we get the following SQL statements in the log:
Code:
00:57:14,717 DEBUG [org.hibernate.SQL] (ajp--127.0.0.1-8009-1)
select
entity1x0_.id as id23_0_,
entity1x0_.name as name23_0_
from
entities.entity1 entity1x0_
where
entity1x0_.id=?
00:57:17,971 DEBUG [org.hibernate.SQL] (ajp--127.0.0.1-8009-1)
select
entity2s0_.ent1_id as ent1_23_1_,
entity2s0_.ent2_id as ent2_1_,
entity2x1_.id as id17_0_,
entity2x1_.name as name17_0_
from
entities.ent1_ent2 entity2s0_
inner join
entities.entity2 entity2x1_
on entity2s0_.ent2_id=entity2x1_.id
where
entity2s0_.ent1_id=?
order by
entity2x1_.sortorder
00:57:18,081 DEBUG [org.hibernate.SQL] (ajp--127.0.0.1-8009-1)
select
entity3s0_.ent2_id as ent1_17_1_,
entity3s0_.ent3_id as ent2_1_,
entity3x1_.id as id28_0_,
entity3x1_.name as name28_0_
from
entities.ent2_ent3 entity3s0_
inner join
entities.entity3 entity3x1_
on entity3s0_.ent3_id=entity3x1_.id
where
entity3s0_.ent2_id in (
?, ?
)
So it seems that the join fetch definition on Entity2 is ignored and a third statement is generated. I would rather have expected the first statement and ONE additional statement like this:
Code:
select
entity2s0_.ent1_id as ent1_421_4_,
entity2x1_.id as ent2_4_,
entity2x1_.id as id427_0_,
entity2x1_.name as name427_0_,
entity3s0_.ent2_id as ent1_427_5_,
entity3x1_.id as ent2_5_,
entity3x1_.id as id429_1_,
entity3x1_.name as name429_1_
from
entities.pp_ent1_ent2 entity2s0_
left outer join
entities.pp_entity2 entity2x1_
on entity2s0_.ent2_id=entity2x1_.id
left outer join
entities.pp_ent2_ent3 entity3s0_
on entity2x1_.id=entity3s0_.ent2_id
left outer join
entities.pp_entity3 entity3x1_
on entity3s0_.ent3_id=entity3x1_.id
where
entity2s0_.ent1_id=?
I know there is a Hibernate property max_fetch_depth but the documentation says it only influences single-ended (...ToOne) associations, and tests prove it. So does anybody have an idea why the FetchMode.JOIN is ignored and if there is a way it is not?
Thanks in advance,
best regards
Flo
Code:
@Entity
@Table(name = "entity1", catalog = "entities")
public class Entity1 implements java.io.Serializable {
private Long id;
private String name;
private Set<Entity2> entity2s = new HashSet<Entity2>(0);
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToMany(fetch = FetchType.LAZY, cascade={CascadeType.PERSIST})
@Fetch(FetchMode.SELECT)
@BatchSize(size = 100)
@JoinTable(name = "ent1_ent2", catalog = "entities", joinColumns = { @JoinColumn(name = "ent1_id", referencedColumnName = "id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "ent2_id", referencedColumnName = "id", nullable = false, updatable = false) })
@OrderBy(value = "sortorder")
public Set<Entity2> getEntity2s() {
return this.entity2s;
}
public void setEntity2s(Set<Entity2> entity2s) {
this.entity2s = entity2s;
}
@Column(name = "name", nullable = false, length = 30)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity
@Table(name = "entity2", catalog = "entities")
public class Entity2 implements java.io.Serializable {
private Long id;
private String name;
private Set<Entity3> entity3s = new HashSet<Entity3>(0);
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToMany(fetch = FetchType.EAGER, cascade={CascadeType.PERSIST, CascadeType.MERGE})
@Fetch(FetchMode.JOIN)
@JoinTable(name = "ent2_ent3", catalog = "entities", joinColumns = { @JoinColumn(name = "ent2_id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "ent3_id", nullable = false, updatable = false) })
public Set<Entity3> getEntity3s() {
return this.entity3s;
}
public void setEntity3s(Set<Entity3> entity3s) {
this.entity3s = entity3s;
}
@Column(name = "name", nullable = false, length = 30)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity
@Table(name = "entity3", catalog = "entities")
public class Entity3 {
private Long id;
private String name;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "name", nullable = false, length = 30)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}