Collection mappings in Hibernate can be configured to sort using a specific comparator.
Consider the following mapping
[sourcecode language=”xml”]
<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>
[/sourcecode]
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
[sourcecode language=”xml”]
<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="natural">
[/sourcecode]
which sorts by natural order
the second option is
[sourcecode language=”xml”]
<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="unsorted">
[/sourcecode]
which tells Hibernate that the Set needs not to be sorted
and the third option is
[sourcecode language=”xml”]
<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="comparatorClass">
[/sourcecode]
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
[sourcecode language=”java”]
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);
}
}
}
[/sourcecode]
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
[sourcecode language=”java”]
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;
}
}
[/sourcecode]
Then your mapping will say something like this
[sourcecode language=”xml”]
<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="com.example.BankAccountShortNameComparator">
[/sourcecode]
In this way Hibernate will use your custom Comparator to sort the set
My primary key is varchar and I’d like to sort by number sorter.
Can I apply my custom comparator to primary key?
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
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 ?
Hi Salvin,
Please share your mapping file.
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.
[code]
todo relationship
priority relationship
[/code]
how do i submit xml code in post? the site uses some special tags i guess…
Todo contains Priority:
todo relationship
priority relationship
actual ordering in priority (alphabetically):
“High”,”Low”,”Medium”
required order:
“High”,”Medium”,”Low”
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"
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
Pingback: 2010 in review « Techspace