-->
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.  [ 2 posts ] 
Author Message
 Post subject: query with a list as example?
PostPosted: Thu Dec 27, 2007 5:05 pm 
Newbie

Joined: Fri Mar 24, 2006 2:07 pm
Posts: 8
Hibernate 2.1 / Oracle10g

I have a simple mapping that contains a list:

Code:
    <class name="PathEventSet" table="path_event_set">
        <meta attribute="generated-class">PathEventSetBase</meta>
       
        <id name="pathEventSetId" type="long" column="path_event_set_id">
            <generator class="sequence">
                <param name="sequence">seq_path_event_set_id</param>
            </generator>   
        </id>

        <list name="pathEvents" table = "path_event_set_order">           
            <key column="path_event_set_id"/>
            <index column="path_event_order"/>
            <element type="string" column="path_event_type" not-null="true"/>
        </list>
    </class>


which works well enough in terms of inserting data into the database, I can make a new PathEventSet object and call setPathEvents with an ArrayList<String> (which represents the type and order) and save it with hibernate and it populates the path_event_set_order table with the correct id, order and type values and puts an entry in the path_event_set table. All Lovely.

My issue arises when later on, say after an app restart, I have a ArrayList<String> of types and I want to find out what the id for it is in the database. Since I'm trying to find the path_event_set_id I can't query by id, I have to instead query by value, which in this case is the list. I have tried creating a new PathEventSet object and setting it's list and trying to use that as an example object for a criteria by example load, but it seems to ignore the list values and just loads all PathEventSets that I have in the database:

Code:
ArrayList<String> pathEvents = getEvents();
PathEventSet peSet = new PathEventSet();               
peSet.setPathEvents(pathEvents);
Example exampleSet = Example.create(peSet).ignoreCase();
List results = session.createCriteria(PathEventSet.class)
        .add(exampleSet).list();


I could write some code that shuffles through the ArrayList<String> myself and build up the appropriate table self joins and where clause segments but that seems like a waste of effort since presumably hibernate can be made to do all that for me if I can just configure it properly.

I am missing something obvious, is this not the way that people model ordered sets of data? Any thoughts would be appreciated. Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 28, 2007 7:32 pm 
Newbie

Joined: Fri Mar 24, 2006 2:07 pm
Posts: 8
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.


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

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.