Logo

NHibernate

The object-relational mapper for .NET

How-To: Using the N* Stack, part 2

 

Last Saturday, I posted the first part in a series about building an ASP.NET MVC application from the ground up using NHibernate and Ninject. It dealt with setting up the structure of your solution and referencing some 3rd party assemblies.

In part 2, we’re going to set up the persistence object model. The persistence object model is a set of objects that we use to persist (save) data to the database.

Warning: This is a sample application. There are widely varying opinions on the correct structure for these types of applications. As with most advanced subjects in the ALT.NET space, Ayende has some great information on the difference between a persistence object model and a domain model. For the purposes of this series, they’re the same thing.

First, we build the structure of our persistence model as plain old CLR objects (POCO). I like to do this in the Visual Studio class designer. It helps keep me focused on the high-level entities and relationships instead of wandering off to do detailed implementation code.

Here’s the model we’ll start with:

image

Let’s look at the relationships between courses and sections. We have a one to many relationship from a Course to it’s Sections represented by an ICollection(Of Section) property in Course. We also have a many-to-one relationship from each section back to it’s Course represented by the Course property on Section.

Public Class Course

    Public Property Sections() As ICollection(Of Section)
        Get

        End Get
        Set(ByVal value As ICollection(Of Section))

        End Set
    End Property

End Class

Public Class Section

    Public Property Course() As Course
        Get

        End Get
        Set(ByVal value As Course)

        End Set
    End Property

    'Other properties here...

End Class
public class Course
{

    public ICollection<Section> Sections {
        get { }

        set { }

    }

}

public class Section
{

    public Course Course {
        get { }

        set { }

    }

    //Other properties here...

}

Now that we have all of that built, there’s a couple of small requirements to use these classes with NHibernate.

  1. All properties and methods must be overridable. That’s virtual for your C# folks.
  2. Unless you’re using a dependency injection bytecode provider, you need a parameter-less constructor. If you don’t know what a bytecode provider is, don’t worry about it. We’ll get in to it later on in the series. If you don’t have any constructors, you’re fine. There’s an implied parameterless constructor. As soon as you add a constructor with parameters, you’ll need to create one without parameters, just for NHibernate.
  3. You need some sort of identity property for your database primary key. This can be inherited from a base class, which is exactly what we’re going to do. Edit: Not true. Thanks for the correction Ayende!
  4. In the case of readonly properties, you have some options. You can tell NHibernate your naming convention for backing fields. I don’t like this. I prefer to make my properties read/write and make the setter protected. If you’re new to NHibernate, you’ve probably never seen this before.
    Public Class Course
        Inherits Entity
    
        Private m_Sections As ICollection(Of Section) = New HashSet(Of Section)
    
        Public Overridable Property Sections() As ICollection(Of Section)
            Get
                Return m_Sections
            End Get
            Protected Set(ByVal value As ICollection(Of Section))
                m_Sections = value
            End Set
        End Property
    
    End Class
    public class Course : Entity
    {
    
        private ICollection<Section> m_Sections = new HashSet<Section>();
    
        public virtual ICollection<Section> Sections {
            get { return m_Sections; }
            protected set { m_Sections = value; }
        }
    
    }

    This is how I set up all of my collection properties. You can manipulate the contents of the collection, but you can't replace it with another instance without inheriting this class and overriding the property. If you were to make this property readonly, you'd have to configure NHibernate to write to m_Sections using reflection. It's sort of a pain, and completely unnecessary. This is easier and accomplishes the same end result.

    Also, notice that we're inheriting from a class called Entity. More on that later.

Let's talk about the database for a minute. Each of these entity classes will eventually become a database table. What will you use for your primary keys? Fabio Maulo has a great post on the different NHibernate primary key generators. He also has this post about why identity columns probably are not the best choice.

So what’s a good choice? Well, that’s a matter of opinion. Thanks to NHibernate, I don’t go spelunking through the database much anymore, so I like guids. You really can use what you like, or rather, what your DBA likes.

Now, where are you going to put these primary keys in your objects? In my opinion, this is really a persistence detail – meaning your objects shouldn’t really be dealing with it. That’s why we’re going to keep it hidden away in the base class. Remember, we’re inheriting from Entity.

Public MustInherit Class Entity

    Private m_ID As Guid

    Public Overridable Property ID() As Guid
        Get
            Return m_ID
        End Get
        Protected Set(ByVal value As Guid)
            m_ID = value
        End Set
    End Property

End Class
public abstract class Entity
{

    private Guid m_ID;

    public virtual Guid ID {
        get { return m_ID; }
        protected set { m_ID = value; }
    }

}

That’s it for today’s post. In part 3, we’ll configure NHibernate and set up our database. For homework, we’re going to flesh out the other properties in our persistence model. Check out the source code in Visual Basic.NET or C#.

(Reposted from my blog)

 


Posted Tue, 11 August 2009 11:21:00 AM by Jason Dentler
Filed under: NHibernate, poid, ASP.NET MVC

comments powered by Disqus
© NHibernate Community 2024