开发者

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 for Address 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 Addresses) query with JOIN can be preferred for performance reasons.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜