Note on sets in hibernate/nHibernate

I just wanted to share this with anyone who is not aware…



Caveat:  After reviewing my original post and the comments that follow I had initially elected to change the container tag in the example below from set to list.  After thinking about it further I’ve returned the tag to ‘set’, since this is after all what I was trying to illustrate in the first place (although understanding the risk of using set should be understood).  Granted, a list probably should have been used, but this was a solution to a problem relating to an existing system that I’m currently working on.  I apologize if it offends your senses, it sort of does mine too, but the tests do pass and the code does work as expected.  Hopefully others facing similar constraints may find it of use in any case.  [:)]


We are using hibernate of my current project, but this should be the same for nHibernate.  In any case, we ran into a situation where we needed to ensure that a collection (Set) on a class that we were mapping needed to ensure the order of list items when used in the middle tier.  The class had a sequenceNumber field that was used to indicate ordinality in the Set.  The knee-jerk solution proposed was to modify the class to support sorting, but it was work that no one wanted to pick up so the code stayed broken.


I, being industriously lazy, didn’t want to do it either but wanted it done none the less.  I had never set the order-by in the hbm configs before but figured this would be as good a reason to use it as any.  So I made one simple change to our mapping file and the broken unit tests magically started passing.  Here’s a code example:


<set
name
=myCollectionOfThings
lazy
=true
inverse
=true
order
-by=SEQUENCE_NUMBER ASC
>
<key>
<column name=THING_HOLDER_FK />
</key>
<one-to-many
class=blah.blablah.ThingHolder
/>
</set>

It’s the “order-by” attribute in the “set” tag is what is used to define the default OrderBy behavior.  The contents are straight SQL that get’s tagged on the end of the rendered prepare statement that is executed against the database.


 


Hope that’s of use!

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Joshua Lockwood

I code stuff and people pay me for it.
This entry was posted in Hibernate, Java. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

7 Responses to Note on sets in hibernate/nHibernate

  1. Brian Yarger says:

    In order for this to work, you’ll also need to make sure that the collection class holding “myCollectionOfThings” preserves order. A HashSet will not, but a LinkedHashSet will, or of course a List would.

  2. James Kovacs says:

    I’m coming from the NHibernate world, but shouldn’t you be mapping this with a list and using an index element? Order-by is SQL and performs the sort in the database by augmenting the SQL query. This means that items added to the collection won’t be in the proper sort order until persisted and reloaded. Using a , items are always in the proper order.



    The one limitation is that has to be zero-based. If you don’t have a zero-based index, then I would use the sort attribute on to specify an IComparer to ensure proper ordering.

    A quick read over the Hibernate docs seems to confirm that Hibernate has similar facilities though attribute/element names are slightly different in cases. See Hibernate docs section 6.2.3 and .

  3. Hibernate supports an arbitrary base for by specifying the “base” attribute (it doesn’t have to be zero-based). NHibernate also supports this in the upcoming 2.0 release (currently in alpha).

  4. jlockwood says:

    @Brian
    I’ve got good test coverage and all is passing, but I do see what you are saying and will look into it. I do think that List<> should be used and not Set (usually use list by default with NHiberante). I’ll go ahead and change the example to reflect this. I believe I would still need the ‘order by’ in the mapping, right?

    @James
    I hear you. As stated above I’ll most likely switch to list. I really don’t want to implement Comparable right now. I think the use of set in the first place was wrong, but I see that it resulted from the process used to generate the ‘Thing’ class.

    @Sean
    I wasn’t aware of that, thanks. Note that the sequence number in the example above is not a database sequence (like in Oracle).

    @All
    The app that I’m working on is a little funky and one could argue that the process used in working on the data end is unecessary. I was trying to minimize needed changes to the hbms because of our process (which I’m hoping to change).

    The process is as follows:
    0. ValueObjects are created for use in the service layer.
    1. Model the DB using Erwin to loosely support the VOs.
    2. Generate the DDL’s from the model in Erwin.
    3. Generate the hbms from the DDLs.
    4. Generate the DataObjects from the hbms.
    5. Create conversion classes to map between the VOs and DOs.

    I’m new to the project and this is my first go at Hibernate. I have quite a bit of NHibernate experience under my belt. The approach we are using is reverse of the process I would normally use (i.e. creating DomainEntities first, then hbms, then schema generation [DDLs]).

    There’s a huge risk with this approach since every time new hbms are generated to support a VO we need to massage the hbm file. We try to only generate the hbms/DOs that are needed due to schema changes. This whole thing is pretty brittle and there’s a huge risk of breaking things with each schema change.

  5. By definition Sets are not ordered. What you want is a List, as James Kovacs mentioned above.

  6. jlockwood says:

    @Ben

    Right, I realize that. As far as the project that I’m working on, the DBA doesn’t want it changed (see my response above). It’s a little wonky, but I have it working with the way our code is structured. I’ll change the example now to reduce confusion between this project and the “real world”. Thanks for the comment!

  7. temojin says:

    It’s possible to set the index to some arbitrary starting value. The problem i have is when i save the collection, the first row’s index value is set to 0. So when i retrieve the collection (via the owning parent object) i get an array out of bounds exception.

    Has anyone else notice this?
    The mapping would look like this:

    Notice in my case i made the inverse=”false” to let this side manage the persistence of the object (on the many-to-one side i put update=”false” insert=”false”

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>