Noah Blumenthal's Blog

January 14, 2009

NHibernate Generic Dictionary Mapping

Filed under: Uncategorized — noahblu @ 4:38 pm

“NHibernate: have I told you today how much I love you?”

The other day I had a good reason to use a generic dictionary and I though hey, I wonder how I’ll get that working with NHibernate…  It’s very simple to persist Generic Dictionarys with NHibernate as I found out.  Let’s see an example…

.NET PSEUDO CODE

Take a person and his favorite or least favorite deserts:

First we have a Person object

class Person
———–
int PersonId
string FirstName
string LastName

And a desert object

class Desert
————
int DesertId
string Name

Now we want to associate a Person with all the deserts and rate how much he likes them (I know, it’s contrived, but it’s simpler than the business case I did this with yesterday).  So first we might create an enum for storing how one feels about a particular dessert (we’ll call it Rating):

enum Rating
———————–
Love,
Like,
Impartial,
Dislike,
Disdain

And then we might add a generic dictionary to the Person object like so:

class Person
———–
string FirstName
string LastName
Dictionary<Desert, Rating> DesertRatings

Looks good.  Now how would we use NHibernate to persist this?  First off, let’s make a slight change to the Person object because NHibernate actually uses IDictionary, so that last line of the Person object would look more like:

IDictionary<Desert, Rating> DesertRatings

DATABASE TABLES

To persist this data we first create the tables in our database.  Assuming we used the code above, I would probably create 3 different tables: 1 to store the Persons, 1 to store Deserts, and 1 to store the association between Persons and their Desert ratings.  The tables might look like this:

PEOPLE
PersonId, int
FirstName, varchar
LastName, varchar

DESERTS
DesertId, int
Name, varchar

PEOPLEDESERTRATINGS  (PersonId and DesertId will be the primary keys since 1 person can only have 1 rating for a specific desert)
PersonId, int
DesertId, int
Rating, int (this will store the integer representation of the enum)

NHibernate Mappings

Now behold the magic of NHibernate.  Let’s take a look at what the Person.hbm.xml file might look like:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<hibernate-mapping xmlns=”urn:nhibernate-mapping-2.2″ assembly=”MyAssembly” namespace=MyNamespace”>
<class name=”Person” table=”People”>
<id name=”PersonId” column=”PersonId” type=”Int32″ unsaved-value=”0″>
<generator class=”native”></generator>
</id>
<property name=”FirstName” column=”FirstName” type=”String” not-null=”true” />
<property name=”LastName” column=”LastName” type=”String” not-null=”true” />
<map name=”DesertRatings” table=”PeopleDesertRatings”>
<key column=”PersonId” />
<index-many-to-many class=”Desert” column=”DesertId” />
<element column=”Rating” type=”MyNamespace.Rating” not-null=”true” />
</map>

</class>
</hibernate-mapping>

That’s all there is too it.  There’s a lot that I didn’t cover here, and this is NOT meant to be a tutorial on how to design your objects or tables.  However, I think I’ve shown how amazingly easy it is to persist this kind of thing using NHibernate.  I didn’t find anything online about this before I tried it and it worked the first time, but I would have felt more comfortable trying it had I seen someone else do it first.  So hopefully this post helps someone feel comfortable diving right in.

Advertisements

7 Comments »

  1. Thanks – terse, simple and very useful example.

    Comment by adante — July 12, 2009 @ 11:38 pm | Reply

  2. Useful example, but my code throws NHibernate.FKUnmatchingColumnsException: Foreign key (FK7F1E6AB72895CA9B:DesertRatings [DesertId])) must have same number of columns as the referenced primary key (DesertRatings [PersonId, DesertId]). Can You post complete code of solution and DB schema? Thanks.

    Comment by Konstantin — July 21, 2009 @ 2:08 pm | Reply

  3. You get collection as IDictionary DesertRatings.
    Are there any way to map collection as IDictionary DesertRatings, where key (of type string) is
    DESERTS.Name?

    Comment by kate — August 5, 2009 @ 8:18 am | Reply

  4. Unfortunately angle brackets isn’t shown. I mean? you get IDictionary _[Desert,Ratings]_ collection, but I want to get IDictionary _[string,Ratings]_ collection,where key (of type string) is
    DESERTS.Name

    Comment by kate — August 5, 2009 @ 8:23 am | Reply

  5. Kate: To map a dictionary with valuetype keys, instead of you should use .

    In your case,

    Comment by adante — August 8, 2009 @ 4:58 am | Reply

  6. ok, replace square with angle brackets 🙂

    instead of [index-many-to-many] you should use [index]

    e.g. [index column=”MyStringKey” type=”string”/]

    Comment by adante — August 8, 2009 @ 4:59 am | Reply

    • Thanks, adante!

      Comment by noahblu — August 9, 2009 @ 1:13 am | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: