NHibernate is an Object Relational Mapper (ORM) for the .NET Runtime. XML Mappings are still the most popular method of mapping persistent classes to their relational tables:
With such change abound, I thought it a great opportunity to layout the fundamentals of XML Mappings. In the process, we’ll also delve into a few core development laws I use regardless of platform.
Elements of Object Oriented Software
Particularly with static languages, I adhere to two core object oriented design principles. These principles were first applied in Design Patterns: Elements of Reusable Object-Oriented Software by The Gang of Four - Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides:
These design principles form the basis for maintainable NTier’d applications both on the J2EE and .NET Runtimes.
Let’s take a look at a domain model that implements these core object oriented design principles. Let’s model a blog Post:
The Post Interface (IPost.cs)
The interface exposes the public properties and methods of a persistent class in your domain:
The Post Implementation (Post.cs)
The Post class implements the IPost interface. Here, we assume the Author class and the Comment class are defined elsewhere:
Each Post has an Author and a list of Comments. In the Post constructor, I create instances of each domain object.
Rarely does a problem domain ever break down to neat hierarchical entities. The majority of domain models are usually composed of another model or a collection of other models that it does work on or relies on.
That’s why understanding object composition is so important. Object composition gives you the freedom to model the world as you see it without the self-imposed restrictions that come with being inheritance focused.
The real problem is inheritance breaks encapsulation because it exposes a subclass to details of it’s parents implementation.
These implementation dependencies can cause problems when trying to reuse a subclass. Should any aspect of the inherited implementation not be appropriate for new problem domains, the parent class must be rewritten or replaced by something more appropriate. This dependency limits flexibility and ultimately reusability.
On the other hand, Object Composition requires objects to respect each others interfaces, which in turn requires us to carefully design interfaces that don’t stop you from using one object with many others. Because objects are accessed solely through their interfaces, we don’t break encapsulation.
Favoring object composition over class inheritance helps you keep each class focused on one task - The Single Responsibility Rule. You classes and class hierarchies will remain small and will be less likely to grow into unmanageable monsters.
###NHibernate XML Mappings
NHibernate XML Mappings are a way to map our domain objects to their corresponding database tables.
Using NHibernate, the database becomes an implementation detail and you can spend more time understanding your problem domain and less time fiddling with database tables.
Here’s how we would map our Post class:
The NHibernate Mapping (Post.hbm.xml)
Here, we’ll assume the Author class is mapped in Author.hbm.xml and the Comment class is mapped in Comment.hbm.xml:
Top to bottom, here are some major key points to take away from this NHibernate class map:
There are time when you don’t need to fetch the entire object graph. Setting default-lazy=”true” ensures NHibernate will only request the entity data you requested at a given time.
Also, if you use lazy loading (which I highly recommend you do), you need to add the virtual keyword to each of your classes’ public properties and methods.
We can all agree orphaned data isn’t a good thing. Set the cascade property to “all-delete-orphan” to delete data that would otherwise have been orphaned forever. This issue generally comes to light when handling custom types or lists of custom types.
System Types - (int, string, bool) are defined using the property tag.
Custom Types - (Author) are defined using the many-to-one tag.
Lists of Custom Types - (List of Comments) are defined using the bag tag with a one-to-many relationship to the Custom Type (Comment). Here, each instance of a Comment has an associated unique Post instance. Therefore, PostId needs to be a public property on the Comment class. Then NHibernate an properly associate each Comment to the correct Post.
Today we covered a modern approach to object oriented programming. We also covered how to flush out a domain model and how to map its custom types in NHibernate.
NHibernate is a fine piece of software. Sometimes the hardest part is understanding how to map your custom classes. I hope this article helps in understanding the mapping between your domain’s custom types and lists of custom types.
Don’t worry, you’ll be an ORM Boss in no time. Godspeed and Happy Coding. Go get ‘em!