Contents tagged with NHibernate

  • NHibernate: Identity columns that are not the primary key

    Sometimes you need a column in your database to automatically increment (like an identity column) in order to provide back to a user say a confirmation number (when an item is added to that table). In NHibernate there's no way to specify this kind of behavior with normal mappings because the column in the Id tag has to be the primary key. Here's a technique we used to do this. 

    Let's say we have a ticketing system (like TicketMaster) and it's going to give back the user a confirmation number after adding their request. The TicketRequest table ID is keyed off of a Guid but we can't provide that back to the user so we need an additional property called ConfirmationNumber (plus we don't want to expose ID fields to the users). 

    Specify your table mappings like so:

    <class name="TicketRequest" lazy="false">
      <id name="Id" type="guid.comb">
        <generator class="assigned"/>
      </id>
    <property name="ConfirmationNumber" generated="insert" insert="false" update="false">
    </class>

    Then in the same mapping file change the ConfirmationNumber column on creation to an identity column using the <database-object> tag:

    <database-object>
    <create>
      ALTER TABLE TicketRequest DROP COLUMN ConfirmationNumber
      ALTER TABLE TicketRequest ADD ConfirmationNumber INT IDENTITY
    </create>
    </database-object>

    There you have it. When you insert your record, you'll be able to use a Guid ID field but provide back an auto-incrementing field to your users.

    Hope that helps.

  • New NHibernate users mailing list setup, join now! Operators are standing by.

    I'm always finding myself Googling an answer to a question about NHibernate (either that or I fire off an email to Oren, although I think I've used up all my chits with him now). The SourceForge project has a mailing list (several of them actually) but they're really aimed at development of NHibernate, not the use of it. I found that a little odd.

    There are the NHibernate User Forums here, however I'm just finding online forums don't work very well. Rather than being able to get emails on my mobile device and respond, I have to log into a web page (usually remembering my username/password) and sift through what's there. With email I can keep it organized either through Gmail or whatever and be able to keep the stuff I like. I'm not trying to subvert the forums and I realize there may be some backlash from this, I'm just trying to provide an alternative. We'll see how it goes.

    I created a new mailing list on Google Groups for NHibernate Users. Here's the blurb:

    Users of NHibernate unite! This group is aimed at people using NHibernate and looking for tips, tricks, or just want to ask a question. Post your code on how you use NHibernate or share some experiences with it here. Good, bad, or ugly, this is the place for it!

    If you're interested in talking about NHibernate and using it, feel free to hook up here. Hopefully this might cut down the Googling everyone has to do for the same questions and provide a bit of a focused group for discussion.

    P.S. The group is set to moderate your first post. This is to confirm your carbon based status in the world. Flip me an email if you're human and I'll approve you.

    Enjoy!

  • Reconsituting Domain Collections with NHibernate

    We ran into a problem using NHibernate to persist our domain. Here's an example of a domain object; an Order class with a collection of OrderLine objects to represent the line in each order placed in the system. In the system we want to be able to check if an order exists or not so we use an anonymous delegate as a predicate on the OrderLine collection:

        7 class Order

        8 {

        9     private IList<OrderLine> Lines;

       10 

       11     public Order()

       12     {

       13         Lines = new List<OrderLine>();

       14     }

       15 

       16     public bool DoesOrderExist(string OrderNumber)

       17     {

       18         return ((List<OrderLine>)Lines).Exists(

       19             delegate(OrderLine line)

       20                 {

       21                     if (line.OrderNumber == OrderNumber)

       22                         return true;

       23                     return false;

       24                 }

       25             );

       26     }

       27 }

       28 

       29 class OrderLine

       30 {

       31     public string OrderNumber;

       32     public int Quantity;

       33     public string Item;

       34     public double Cost;

       35 }

    This is all fine and dandy but when we reconsistute the object from the back-end data store using NHibernate, it blows its head off with an exception saying it can't cast the collection to a list. Internally NHibernate creates a PersistantBag object (which implements IList) but can't be directly cast to a List, so we can't use our predicate.

    There's a quick fix we came up with which is to modify the DoesOrderExist method to look like this instead:

       16 public bool DoesOrderExist(string OrderNumber)

       17 {

       18     List<OrderLine> list = new List<OrderLine>(Lines);

       19     return (list.Exists(

       20         delegate(OrderLine line)

       21             {

       22                 if (line.OrderNumber == OrderNumber)

       23                     return true;

       24                 return false;

       25             }

       26         );

       27 }

    This feel dirty and smells like a hack to me. Rebuilding the list from the original one when we want to find something? Sure, we could do this and cache it (so we're not recreating it every time) but that just seems ugly.

    Any other ideas about how to keep our predicates intact when reconsituting collections?

  • Returning Generic Lists from NHibernate

    This was an "aha" moment for me this morning as I was building a small spike project to figure out how we can incorporate NHibernate as our data access layer and still be a happy loosely coupled Smart Client.

    Beyond the fact that I have to create a class library to hold all my interfaces for my domain (as I need to inject my data provider into the domain repository and can't have circular references to NHibernate, but that's another story) I was finding it frustrating that I was getting ArrayLists back from NHibernate.

    Here's a method that gets me back a list of customer objects from the NHibernate session:

        1 public List<ICustomer> GetCustomers()

        2 {

        3     List<ICustomer> customers = new List<ICustomer>();

        4     ITransaction tx = null;

        5 

        6     try

        7     {

        8         tx = Session.BeginTransaction();

        9         customers = (List<ICustomer>)Session.CreateCriteria(typeof(ICustomer)).List();

       10     }

       11     catch (HibernateException)

       12     {

       13         if (null != tx)

       14         {

       15             tx.Rollback();

       16         }

       17     }

       18 

       19     return customers;

       20 }

    Typical stuff and the example you see everywhere. However I like dealing with a generic List<ICustomer> object rather than an IList (some will argue it's the same thing). The code above compiles fine, but when you run it you get an error as it cannot convert an ArrayList to a List<ICustomer> no matter how hard it tries. A quick check on the Session class in Reflector revealed to me there was a generic List<T> method. One line of code change was all that was needed and voila:

        1 public List<ICustomer> GetCustomers()

        2 {

        3     List<ICustomer> customers = new List<ICustomer>();

        4     ITransaction tx = null;

        5 

        6     try

        7     {

        8         tx = Session.BeginTransaction();

        9         customers = (List<ICustomer>) Session.CreateCriteria(typeof (ICustomer)).List<ICustomer>();

       10     }

       11     catch(HibernateException)

       12     {

       13         if(null != tx)

       14         {

       15             tx.Rollback();

       16         }

       17     }

       18 

       19     return customers;

       20 }

    Subtle but the change in liine 9 from List() to List<ICustomer)() gets me a collection of List<ICustomer> objects coming back from NHibernate. Silly I know, but something to watch out for as all the examples out there say call List() to get an IList back but this way you can get a generic list of whatever objects you want.

    kick it on DotNetKicks.com