Techspace

IT happens only in IT

Sorting Hibernate Set using a comparator

Collection mappings in Hibernate can be configured to sort using a specific comparator.

Consider the following mapping

<hibernate-mapping>
<class name="com.example.Person" table="PERSON">
......

<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="natural">
	<key>
		<column name="BANK_ACCOUNT_ID" precision="29" scale="0" not-null="true" />
	</key>
	<one-to-many class="com.example.BankAccount" />
</set>

......
</class>
</hibernate-mapping>

In the example above Hibernate will order the bankAccounts set according to their natural order. If the BankAccout class implements Comparable interface, compareTo method will be used to sort the Set.

What if you want to sort the set differently? What if you want to use a comparator to sort the set.
The sort attribute can have three possible values

The first option is

 <set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="natural">

which sorts by natural order

the second option is

 <set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="unsorted">

which tells Hibernate that the Set needs not to be sorted

and the third option is

 <set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="comparatorClass">

where you specify what comparator should be used to sort the Set.

Let’s see it through code example. For example suppose class BankAccount is defined as below

package com.example;
//import statements

public class BankAccount implements Comparable<BankAccount>, Serializable{

private String accountName;
private String accountShortName;
//getter and setter methods

    public int compareTo(BankAccount that) {

        final int BEFORE = -1;
        final int AFTER = 1;

        if (that == null) {
            return BEFORE;
        }

        Comparable thisAccountName = this.getAccountName();
        Comparable thatAccountName = that.getAccountName();

        if(thisAccountName == null) {
        	return AFTER;
        } else if(thatAccountName == null) {
        	return BEFORE;
        } else {
        	return thisAccountName.compareTo(thatAccountName);
        }
    }
}

In this case sort=”natural” will sort using the above compareTo method which compares the accountName to sort.
Now suppose you want that for this specific mapping you want the collection to be sorted by, say, accountShortName. You will define a Comparator like this

package com.example;
//import statements
public class BankAccountShortNameComparator implements Comparator<BankAccount>{
	public int compare(BankAccount o1, BankAccount o2) {
		if(o1!=null && o2!=null && o1.getAccountShortName()!=null && o2.getAccountShortName()!=null) {
			return o1.getAccountShortName().compareTo(o2.getAccountShortName());
		}
		if(o1!=null && o2!=null) {
			return o1.compareTo(o2);
		}

		return 0;
	}
}

Then your mapping will say something like this

	<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="com.example.BankAccountShortNameComparator">

In this way Hibernate will use your custom Comparator to sort the set

Advertisement

November 10, 2008 - Posted by | Hibernate | , ,

11 Comments »

  1. My primary key is varchar and I’d like to sort by number sorter.
    Can I apply my custom comparator to primary key?

    Comment by MethoD | January 6, 2009 | Reply

  2. Hello,
    I could not get your question fully. What number sorter you want to use? Is your primary key a Class? What is the relation between the number and the primary key? Please explain the scenario

    Comment by Paras | January 6, 2009 | Reply

  3. What if there is no set ?

    I am using a Many-to-one relationship where
    i want to custom sort the child, wht do i do ?

    Comment by salvin francis | May 6, 2009 | Reply

    • Hi Salvin,
      Please share your mapping file.

      Comment by Paras | May 6, 2009 | Reply

      • well i m sorry i cant share tht wid you (company code)

        but here is the thing i can say:

        something called “todo” in my application has a many-to-one relation with “priority”

        so todo relation is:

        and the priority hbm file contains:

        the HQL query (i am not allowed to use SQL) uses orderby

        The issue is priority is sorted Alphabetically, however
        this is not correct for “High”,”Medium”,”Low” (since “L” comes before “M”)
        someone suggested me to use lowercase for “l” but i consider that a Hack.

        Comment by salvin francis | May 7, 2009

      • todo relationship
        
        priority relationship
        

        Comment by salvin francis | May 7, 2009

  4. how do i submit xml code in post? the site uses some special tags i guess…

    Comment by salvin francis | May 7, 2009 | Reply

  5. Todo contains Priority:

    todo relationship

    priority relationship

    actual ordering in priority (alphabetically):
    “High”,”Low”,”Medium”

    required order:
    “High”,”Medium”,”Low”

    Comment by salvin francis | May 7, 2009 | Reply

  6. Todo contains Priority:
    todo relationship
    <code>
    <many-to-one
    name="prtyHdr"
    class=[priority class name]
    not-null="true"
    >
    <column name="PR_ID"/>
    </many-to-one>
    </code>

    priority relationship
    <code>
    <set
    name="todoLogs"
    lazy="true"
    inverse="true"
    cascade="all"
    >
    <key>
    <column name="PR_ID"/>
    </key>
    <one-to-many
    class=[todo class name]
    />
    </set>
    </code>
    actual ordering in priority (alphabetically):
    "High","Low","Medium"
    required order:
    "High","Medium","Low"

    Comment by salvin francis | May 7, 2009 | Reply

  7. What I understand from the scenario that you have list of to-dos and every ToDO has a priority.

    I am confused at the exact scenario. I guess the scenario could be one of the following

    i) Scenario 1 – You are showing the list of ToDos on some page and by default the ToDos are coming in the order of HLM and you want in HML order. In that case you must be holding ToDos in some collection and that collection will sort in the order of natural sorting. In order to override that your ToDo class has to implement Comparable interface and you have to write compareTo method accordingly. It is a good idea to implement equals and hashcode also for ToDo class.
    One more thing, the collection you must use for this should be TreeSet or any collection implementing SortedSet interface. I guess currently the results of your HQL query is being stored in Arraylist or something

    ii)Scenario 2 – Another scenario could be you are showing priorities in the dropdown or somewhere and your browser is shoing priorites in wrong order. In that case try Priority should implement comparable interface or your view layer should re-order

    Please not that neither of this scenario is related to my original blog post where you have set for a class. In this case you don’t have Set you have many to one relationship. One ToDo has only one priority. My blog post could be relevant had you had multiple priorities for one ToDo and you want to order them in some specific pattern.

    Hope this makes it clear. Let me know if you have any questions

    Comment by Paras | May 8, 2009 | Reply

  8. [...] Sorting Hibernate Set using a comparator November 200810 comments 5 [...]

    Pingback by 2010 in review « Techspace | January 4, 2011 | Reply


Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.