These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 22 posts ]  Go to page Previous  1, 2
Author Message
 Post subject:
PostPosted: Mon May 01, 2006 6:52 pm 
Newbie

Joined: Sun Mar 05, 2006 7:36 pm
Posts: 4
Code:
Set set = new LinkedHashSet();
set.addAll(query.list());   
return set;


Well that works but you will loose your sorting if you have any because the SET is not able to guarantee the order of the items

Cheers
Rolf


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 3:37 am 
Regular
Regular

Joined: Thu Oct 13, 2005 4:19 am
Posts: 98
I just replaced all my loadAll methods with HQL 's and it solved...

personDao.loadAll()

=>

personDao.find()
from Person person join fetch person.address order by name

_________________
http://www.ohloh.net/accounts/ge0ffrey


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 09, 2008 9:18 am 
Newbie

Joined: Tue Feb 14, 2006 9:50 am
Posts: 9
Location: Paris - France
Funny, I fell over this same problem today, two years after...

Thomson wrote:
The problem is, that there is no elegant solution.


You say there is no elegant solution, but apparently you do have it, in the code of Hibernate itself. That is because if I simply change the use of Criteria by a HQL query (Session.createQuery()) it works just as expected, no duplicated rows...


Top
 Profile  
 
 Post subject: Re: Duplicate Parent record when joined with one-to-many
PostPosted: Mon Mar 08, 2010 6:18 pm 
Newbie

Joined: Mon Mar 08, 2010 6:08 pm
Posts: 1
I was having this problem also. I was expecting one person object populated with two 'child' address objects. But instead I was getting back two duplicate person objects, with one child address object each.

I found this discussion here:
http://forum.springsource.org/archive/index.php/t-24064.html

Adding the Criteria.DISTINCT_ROOT_ENTITY parameter made it work how I expected it to.

Code:
        Criteria criteria = getSession().createCriteria(Person.class);
        criteria.add(Restrictions.eq(COMPOSITE_ID + "." + ATTRIBUTE_PERSON_ID, inPersonId));       
        criteria.setFetchMode("addresses", FetchMode.JOIN);
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
        return criteria.list();


Top
 Profile  
 
 Post subject: Re: Duplicate Parent record when joined with one-to-many
PostPosted: Tue Mar 09, 2010 9:47 am 
Newbie

Joined: Tue Mar 09, 2010 9:10 am
Posts: 1
Hi guys! I have found an elegant solution to this problem. With code below it is possible to truly paginate the result of a hibernate query, yet avoid duplicate parent problem. But - only when using criteria api.

The idea is the following:

  • First a projection is created which returns only distinct id's of records we wish to retrieve, with applied pagination.
  • Second, based on retrieved id's, whole records are retrieved, with no worries that they are duplicated, because pagination was accomplished at previous step.
  • Last step - the resulting records are passed through a LinkedHashSet to eliminate duplicates yet preserve sort order.

Here is my spring-managed dao implementation. I did a lot of research to accomplish this solution, an I would be pleased if someone else will find it useful:

Code:
public class CriteriaDao extends HibernateDaoSupport {

    public int getCount(DetachedCriteria criteria) {
        return (Integer) getHibernateTemplate().findByCriteria(createCountProjection(criteria)).get(0);
    }

    /**
     * This implementation do the real pagination of entities, and is also aware of duplicate parent entities problem.
     * It heavy relies on criteria projection api to avoid the duplicate problem, yet accomplish the true pagination.
     */
    public <T> List<T> getAll(DetachedCriteria criteria, SortAndPagingParams params) {
        DetachedCriteria idProjection = createIdProjectionPreservingSort(criteria, params);
        List<Long> idList = getHibernateTemplate().findByCriteria(idProjection, params.getFirst(), params.getCount());
        DetachedCriteria idListCriteria = createGetByIdListCriteria(criteria, params, idList);
        List<T> rezultWithDuplicates = getHibernateTemplate().findByCriteria(idListCriteria);
        List<T> rezult = distinctList(rezultWithDuplicates);
        return rezult;
    }

    protected static DetachedCriteria createSortedCriteria(DetachedCriteria criteria, SortAndPagingParams params) {
        DetachedCriteria rez = copy(criteria);
        if (params.getSortProperty() != null) {
            rez.addOrder(params.isSortAsc() ? Order.asc(params.getSortProperty()) :
                    Order.desc(params.getSortProperty()));
        }
        return rez;
    }

    protected static DetachedCriteria createCountProjection(DetachedCriteria criteria) {
        DetachedCriteria rez = copy(criteria);
        rez.setProjection(Projections.countDistinct("id"));
        return rez;
    }

    /**
     * List the given criteria and return only distinct values.
     *
     * @see <a href="https://forum.hibernate.org/viewtopic.php?t=955186">Duplicate Parent record when joined with
     *      one-to-many</a>
     *      <p/>
     * @see <a href="https://www.hibernate.org/117.241.html">fetch produces duplicate entries</a>
     */
    @SuppressWarnings({"unchecked"})
    protected static <T> List<T> distinctList(List<T> initialList) {
        return new ArrayList<T>(new LinkedHashSet<T>(initialList));
    }

    /**
     * Copy (deep clone) the provided criteria using serialization.
     *
     * @see <a href="https://forum.hibernate.org/viewtopic.php?t=939781">Cloning criteria using serialization</a>
     */
    protected static DetachedCriteria copy(DetachedCriteria criteria) {
        try {
            ByteArrayOutputStream baostream = new ByteArrayOutputStream();
            ObjectOutputStream oostream = new ObjectOutputStream(baostream);
            oostream.writeObject(criteria);
            oostream.flush();
            oostream.close();
            ByteArrayInputStream baistream = new ByteArrayInputStream(baostream.toByteArray());
            ObjectInputStream oistream = new ObjectInputStream(baistream);
            DetachedCriteria copy = (DetachedCriteria) oistream.readObject();
            oistream.close();
            return copy;
        } catch (Throwable t) {
            throw new HibernateException(t);
        }
    }

    protected static DetachedCriteria createIdProjectionPreservingSort(DetachedCriteria criteria, SortAndPagingParams params) {
        DetachedCriteria rez = createSortedCriteria(criteria, params);
        rez.setProjection(Projections.distinct(Projections.id()));
        return rez;
    }

    protected static DetachedCriteria createGetByIdListCriteria(DetachedCriteria criteria, SortAndPagingParams params,
                                                                List<Long> idList) {
        DetachedCriteria rez = createSortedCriteria(criteria, params);
        rez.add(Restrictions.in("id", idList));
        return rez;
    }
}


Code:
/**
* Data passed from data provider to dao layer, containing information about sort and paging.
*
* @author Denis Bogdanas
*/
public class SortAndPagingParams {
    private String sortProperty;
    private boolean sortAsc;
    private int first;
    private int count;

    public SortAndPagingParams(String sortProperty, boolean sortAsc, int first, int count) {
        this.sortProperty = sortProperty;
        this.sortAsc = sortAsc;
        this.first = first;
        this.count = count;
    }

    public String getSortProperty() {
        return sortProperty;
    }

    public boolean isSortAsc() {
        return sortAsc;
    }

    public int getFirst() {
        return first;
    }

    public int getCount() {
        return count;
    }
}

This dao is able to:
  • Use as input any criteria containing restrictions and subcriteria's
  • Retrieve record count
  • Retrieve records sorted by arbitrary parent property
  • Retrieve records paginated
  • Avoid duplicate parent problem in one-to-many, many-to-many associations
  • Leave input criteria unchanged, thus reusable
  • Ideally suited to be used in a wicket DataProvider

Enjoy!


Top
 Profile  
 
 Post subject: Re: Duplicate Parent record when joined with one-to-many
PostPosted: Mon Mar 14, 2011 11:20 am 
Newbie

Joined: Tue Mar 01, 2011 8:54 am
Posts: 5
Hi all!
I've found this thread while googling solution for similiar problem: sorting and filtering with one-to-many relationship.
Here is teh solution(Get/Set stuff omitted):
Code:
class Parent {
  private List<Child> children;
}
class Child {
  private String name;
}

select distinct p, (select min(c.name) from p.children c) from Parent p
[any joins]
where [anything]
order by 2

So the solution is - use distinct to eliminate duplicates. If SQL forces you to add unnecessary items to select list(i.e. sorting field) - use subqueries after select or where clause. This should be enough for most cases.


Top
 Profile  
 
 Post subject: Re: Duplicate Parent record when joined with one-to-many
PostPosted: Thu Jan 19, 2012 7:25 am 
Newbie

Joined: Thu Jan 19, 2012 7:21 am
Posts: 1
denis.bogdanas wrote:
Hi guys! I have found an elegant solution to this problem. With code below it is possible to truly paginate the result of a hibernate query, yet avoid duplicate parent problem. But - only when using criteria api.

The idea is the following:

  • First a projection is created which returns only distinct id's of records we wish to retrieve, with applied pagination.
  • Second, based on retrieved id's, whole records are retrieved, with no worries that they are duplicated, because pagination was accomplished at previous step.
  • Last step - the resulting records are passed through a LinkedHashSet to eliminate duplicates yet preserve sort order.

Here is my spring-managed dao implementation. I did a lot of research to accomplish this solution, an I would be pleased if someone else will find it useful:

This dao is able to:
  • Use as input any criteria containing restrictions and subcriteria's
  • Retrieve record count
  • Retrieve records sorted by arbitrary parent property
  • Retrieve records paginated
  • Avoid duplicate parent problem in one-to-many, many-to-many associations
  • Leave input criteria unchanged, thus reusable
  • Ideally suited to be used in a wicket DataProvider

Enjoy!



Wuou! Looks pretty cool! :) I will give it a try ;). Thanks very very much for share your code :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 22 posts ]  Go to page Previous  1, 2

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.