Hibernate Criteria resulting in cartisian product not so with HSQL: Spring Template issue?
I have two entities Customer
and Address
.
Let's say John (Customer
) has five addresses, then the below two methods return different results
import org.springframework.orm.hibernate3.HibernateTemplate;
@SuppressWarnings("unchecked")
public List<Customer> getByNameCriteria(String firstName)
{
DetachedCriteria criteria = DetachedCriteria.forClass(Customer.class);
criteria.add(Restrictions.eq("firstName", firstName));
return (List<ReposTable>)hibernateTemplate.findByCriteria(criteria);
}
@SuppressWarnings("unchecked")
public List<Customer> getByNameHSQL(String firstName)
{
return (List<Customer>) hibernateTemplate.findByNamedParam("from Customer t where t.firstName=:firstName","firstName",firstName);
}
Client Code snippet
List<Customer> allCustomers1 = rtRep.getByNameCriteria("John");
--> returns 5 rows : with a list of addresses for each of the row
List<Customer> allCustomers2 = rtRep.getByNameHSQL("John");
--> returns 1 row : with a list of addresses
Customer to Address is one to many association as follows
@OneToMany(targetEntity=Address.class, fetc开发者_StackOverflow社区h = FetchType.EAGER, mappedBy="customer" )
@Cascade (value={CascadeType.SAVE_UPDATE })
private Set<Address> addresses = new HashSet<Address>();
Question:
Why is the criteria behaving wrong, it is issuing a cartesian product query where as HSQL is issues two separate queries, one for
Customer
and one forAddress
and showing the expected result.Does this have to do with: setResultTransformer, Distinct root entity issues, please clarify.
Thanks
It's a well-known behaviour (though I can't find any source where it's clearly defined as valid).
You need to apply result transformer
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
or configure Hibernate to fetch your relationship with SELECT
:
@OneToMany(targetEntity=Address.class, fetch = FetchType.EAGER, mappedBy="customer" )
@Cascade (value={CascadeType.SAVE_UPDATE })
@Fetch(FetchMode.SELECT)
private Set<Address> addresses = new HashSet<Address>();
Note that under some circumstances (especially if you expect the query to return many Customers
, and each Customer
has a few Address
es) query with JOIN
can be preferred for performance reasons.
精彩评论