I have a very specific 2 part question, which I really really hope hasn’t been asked before:)
First the context
I have some Hibernate beans with lazy associations between them such as:
@Entity
public class SalesData {
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(nullable = false)
public Product getProduct() {
return product;
}
}
and then there’s:
@Entity
public class Product {
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public Set<SoundRecording> getSoundRecordings() {
return soundRecordings;
}
}
and finally:
@Entity public class SoundRecording {
}
Now if I make a Criteria query where I add aliases for the SalesData to Product relationship and then for the Product to SoundRecording, like so:
Criteria criteria = session.createCriteria(SalesData.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.createAlias("product", "p");
criteria.createAlias("p.soundRecordings", "s");
I can see in Hibernate’s log that he generates SQL such as:
select ... from SalesData this_
inner join Product p1_ on this_.product_id=p1_.id
inner join SoundRecording s5_ on p1_.id=s5_.product_id
where ...
when I call criteria.list() which is exactly what I want. However If I do:
salesDatas.getProduct().getSoundRecordings(0);
I can see in the log that Hibernate has made another specific SQL select query to retrive this association:
select ... from SoundRecording soundrecor0_ where soundrecor0_.product_id=?
My question is then:
Is this normal? My goal here is to load in one shot (with one SQL query) all that I need specifically so I can avoid these n+1 selects. I thought using alias is one way to do this, especially since I can clearly see that his generates an inner join between the tables. If I use an explictit fetchMode(Join) then hibernate won’t issue all the extra selects, it will be content with the initial select with many (outter) joins. Why is it then that the same is not true for the alias-generated joins?
An alias or subcriteria is used to create a join. This join might have two goals:
If you want 1 and don’t want 2, then a fetch is not necessary, and you should thus not call
setFetchMode()). If you want 2, then a fetch is necessary.Example: you might want to search all the products with an order in the current month, but not be interested at all in the fields of the order. In this case, a fetch for the orders of the product is unnecessary, and would be very costly if some products have hundreds or thousands of orders in the month.