Reputation: 1259
I'm replacing an application used at work, using Hibernate with an existing database. I can't modify the database since it's in use with other processes. When Hibernate pulls the main object from the db, the child objects are put in an unordered set. I've never really dealt with sets or sorting sets much before.
I need to display the last (chronologically) child for each set. There are no dates stored for the child objects, but since the id field in the db is AUTO_INCREMENT, I can sort them by id in lieu of a date.
One of the complaints about the existing system in use is that it's really, really slow. I'd like to show a definite increase of speed with the new application.
Given a Person object (variable name "off") with 0 to n "home addresses", I'm using:
Set addressSet = off.getAddresses();
List<Address> addressList = new ArrayList<>();
Iterator i = addressSet.iterator();
while(i.hasNext()){
addressList.add((Address) i.next());
}
Collections.sort(addressList, new AddressComparator());
Address a = null;
if(addressList.size()>0){
a = addressList.get(addressList.size()-1);
}else{
a = new Address(); //creates new Address object with empty strings
//for fields
}
My simple comparator is:
public int compare(Address t, Address t1) {
return t.getId().compareTo(t1.getId());
}
My question: Through either Java or Hibernate, is there a faster method to sort the sets?
Upvotes: 1
Views: 480
Reputation: 66411
From my point of view, you don't need to sort at all. Use
Collections.max()
or
Collections.min()
with your custom comparator provided to find the address you want. This has O(n) run time in worst case compared to O(nlog(n)) sorting time since you do not sort and only iterate your set once. The positive part also is that you don't need to convert your Set
to List
as the max and min methods work with any Collection
instance.
Another advantage (at least for me) is that Collections
utilities are part of the java runtime, so you don't need to add any third-party libraries.
Upvotes: 3
Reputation: 23246
You can sort at the database level in JPA/Hibernate by using the @OrderBy property where the sort is on a non-nested property. So in your case you can do this.
e.g.
@OneToMany
@OrderBy("id");
public Set<Address> addresses;
and Hibernate will ensure the collection is in a sorted set.
If the sort field happened to be on a nested property (which it isn't in your case) e.g. person.address.town.population then you can still have Hibernate deal with sort using the Hibernate specific (non-JPA) @Sort annotation which will ensure a sorted set as above but will sort using an in memory sort rather than a DB order by clause.
@OneToMany
@Sort(//natural or specify a comparator);
public Set<Address> addresses;
That does not get you the most recent address of course. If you don't want to change the mapping from Set to List which would allow you get the latest based on index, then you could also do this in the Database tier by various means e.g. by creating a view based on max address id for each person.
@Entity
@Table(name = "vw_most_recent_addresses"
public class MostRecentAddress extends Address{
}
public class Person{
@OneToMany
@OrderBy("id");
public Set<Address> addresses;
@OneToOne
public MostRecentAddress mostRecentAddress;
}
Upvotes: 0
Reputation: 103
You can do this without temporary List.
TreeSet sortedSet = Sets.newTreeSet(new AddressComparator());
sortedSet.addAll(off.getAddresses());
return sortedSet.first(); // or sortedSet.last() see what is suitable for you
Details on Sets.
UPD.
Please also see solution with Guava Ordering. It will allow you to get max element without temporary collection at all.
Ordering<Adress> ordering = Ordering.from(new AddressComparator());
return ordering.max(off.getAddresses());
Upvotes: 0
Reputation: 804
I'm not sure if there are multiple sets, but from the code it seems like you are just getting the Address
with the highest id. This can be achieved with the following sql, which wouldn't require sorting.
select * from table where id = (select max(id) from table);
Upvotes: 0