Well to answer my own question, I don't think there is anyway to get hibernate to magic up the query by example or use HQL to bind a list into a query as I would like. Maybe I'm wrong but I couldn't work out how to make hibernate do this. That said, there are two solutions to the problem. One is to just do the query myself:
Code:
public static Long getEventId (Session session, ArrayList<String> pathEvents) throws HibernateException
{
StringBuffer joinTables = new StringBuffer();
for (int ii = 0; ii < pathEvents.size(); ii++) {
if (ii > 0) {
joinTables.append(", ");
}
joinTables.append("PathEventOrderedSet peos" + ii);
}
StringBuffer whereClause = new StringBuffer();
for (int ii = 0; ii < pathEvents.size(); ii++) {
if (ii > 0) {
whereClause.append(" and ");
}
whereClause.append("peos" + ii + ".order=" + ii + " and peos" + ii + ".type = '" + pathEvents.get(ii) + "'");
}
List results = session.createQuery("select peos0.pathEventSetId from " + joinTables + " where " + whereClause).list();
session.evict(pathEvents);
int resultCount = results.size();
if (resultCount == 1) {
return (Long) results.get(0);
} else if (resultCount == 0) {
return null;
}
String error = "Got more than one result for path event!";
log.error(error + "Size: " + results.size() + " Events: " + pathEvents.toString());
throw new HibernateException(error);
}
Which works fine for me, but I know the number of items in my list is going to be small and the total table I am self joining is going to to be small so the query performance should be super reasonable.
The other solution is to make the set table contain a hash_key field in addition to the the id of the list we care about. So when one goes to save a PathEventSet on calls setPathEvents(List) and in the code for setPathEvents you traverse the list and build a hashkey for that particular ordered list and call myPathEvent.setHashKey(theKey) and save it.
So basically change the setter from:
Code:
public void setPathEvents(List<String> events) {
this.events = events;
}
to
Code:
public void setPathEvents(List<String> events) {
setHashKey(buildKey(events));
this.events = events;
}
public static String buildKey (List<String> events) {
..iterate over the events and make a hash key, I used a StringBuffer and took the md5sum of the joined together string of all events.
}
Then in the future when you want to find the id for a particular ordered list you can just do something like "from PathEventSet where hashKey = :hashKey" and set the hashKey using the buildKey function from the object. The only problem of course is if you get a hash collision. This should be very improbable if you are using something like md5sum and not hashing public data (i.e., so a user can't engineer collisions) but depending on your application that might not be good enough. You could keep using the hash solution but check the size of your results list (which you should be doing anyway) and if it is greater than one then you had a collision and you should now use the slower self joined HQL query method to resolve the collision.
Anyway, maybe that will be useful for someone else.