Introduction

Whether you are developing a small or a big application, you always have to deal with data. It's even a critical part of an application. The problem is that this is a tedious, repetitive work, which consumes a lot of time we would prefer to spend on other parts of the application. To solve these problems, multiple solutions exist. One of these solutions are object-relational mapping tools (O/RM). Their goal is to simplify the creation of data access layers, automate data access, or generate data access code. As in life, we in the Information Technology industry must often have to choose between multiple choices sometimes having to choose between apples and oranges when making technology decisions.This also applies to object-relational mapping tools.The question begs: Which O/RM tool is the best solution? Two of the most popular O/RM tools in the .NET world includes Microsoft’s Entity Framework and NHibernate ( a .NET port from the Java’s Hibernate tool).

Sample Application

This article will demonstrate a sample application that will test drive both Microsoft’s Entity Framework and NHibernate as plug-able options in a N-Tier application.To allow these two O/RM tools to be plug-able, this application will implement the Abstract Factory Design Pattern.

The Visual Studio solution for this sample application consists of the following projects.

The Abstract Factory Design Pattern

Design patterns are recurring solutions to software design problems you find again and again in real-world application development. The Abstract Factory pattern used in this sample application derives from The Gang of Four (GoF) patterns publication.

The Abstract Factory design pattern defines an interface containing factory methods which decouple the client from the concrete (actual) classes required to instantiate a family of related products. Thus the client need know nothing about the actual concrete implementations.

The ORMDataServices project implements a factory of OR/M factories.Implementing an abstract data factory begins with creating an interface. In the application, an IDataFactory interface will be created that makes reference to a more concrete interface called ICustomerDataService.

As stated before, this application defines a factory of factories. A separate discrete factory is defined – one each for the Entity Framework and NHibernate. Each factory will implement the ICustomerDataService and IDataFactory interfaces. Implementing these interfaces will allow the discrete factories to pass through the "food chain" up to the calling client code.

At the very top of the food chain is the DataAccess class. This class will determine which concrete data service factory to use based on a DataFactory appsettings as set in the web.config file in the MVC web application.

In the above code snippet, the constructor instantiates the data factory and returns the customer data service. The methods of the application service make no direct reference to the lower level factory methods for either the Entity Framework or for NHibernate. The application code is generic in nature, which allows this application to plug any number of object relational mappers.

The data factories also implement the IDataService interface which includes signatures to allow the application services to begin and commit transactional data.

Installing and Setting Up NHibernate 3.0

NHibernate is a mature, open source object-relational mapper for the .NET framework. Downloading the latest version of Nhibernate can be located at http://nhforge.org, the official new home for the NHibernate for the .NET community.

NuGET

Alternately, you can install NHibernate using NuGet. NuGet is a Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects that use the .NET Framework. When you add a library or tool, NuGet copies files to your solution and automatically makes whatever changes are needed in your project, such as adding references and changing yourapp.config orweb.config file. When you remove a library, NuGet removes files and reverses whatever changes it made in your project so that no clutter is left.

The key assemblies for NHibernate include:

Nhibernate

Nhibernate.ByteCode.Castle

Castle.Core

Iesi.Collections

Antlr3.Runtime

Remotion.Data.Linq

WEB.CONFIG/APP.CONFIG For NHibernate

Because NHibernate is designed to operate in many different environments with various different ways to configure and use NHibernate, it was a bit challenging setting it up and getting it up and running. I found several different ways developers were configurating and using NHibernate. I even found many different configuration setups and not all of them seemed to work. Eventually I found the below web.config settings that worked.

Three key pieces in the web.config settings are specifying the namespace urn:nhibernate-configuration-2.2 (and not confusing it with the version of NHibernate), setting a database dialect that NHibernate should use and as per usual, setting up the database connection string.

One of the things that jumps out at you as an advantage of NHibernate, is it's support for many different databases through it's database dialect configuration - including support for the many different versions of Microsoft SQL-Server, Oracle and DB2.

POCO Classes

The Entity Framework comes with a modeling tool that lets you design your domain and database objects - including using either of the following three options:

Database First

Model First

Code First

Since this sample application will be using both the Entity Framework and NHibernate, I have chosen to use a "Code First" approach to creating my domain objects by creating POCO classes for my domain objects.

The above Customerclass will be mapped to the Customer table in SQL-Server through both NHibernate and the Entity Framework.

XML Mapping for NHibernate

Nhiberate uses an XML mapping file to define a mapping between an entity and the corresponding table in the database. There are many ways to implement and configure NHibernate mapping files upon initialization of a NHibernate configuration start up. In this application I created a separate project called ORMNHibernateMaps.

The below xml mapping maps the customer entity. The file has a naming convention of Customer.hbm.xml. One of the tricks to this set-up is to make sure you also save the file as an embedded resource in the Visual Studio project. Searching many blogs I have found this to be a common missed set-up step. Later the ORMNHibernateMaps assembly will be referenced by NHibernate.

Looking at the mapping file above, you can see references to each column in the Customer table - including a reference to how the CustomerID gets generated - in this case, the CustomerID is defined in SQL-Server as an IDENTITY column.

Two nice pieces in the XML mapping is that your POCO classes can have a different naming convention than your database objects have - which is often the case. You can also add attributes in the XML file that lets you have greater control of the generated CRUD commands. Setting the attribute dynamic-update="true" tells NHibernate to only update those columns that have changed when generating an UPDATE statement.

Initializing NHibernate

The NHibernateDataService initializes NHibernate by creating an NHibernate configuration object and making a reference to the assembly that contains the XML mapping files as embedded resources. Alternately, you can also add the XML mapping files individually as loose files.

Installing and Setting-Up Entity Framework CTP 5

The latest Entity Framework Feature Community Technology Preview (CTP5) is available for download from Microsoft’s download site. This CTP is a preview of the Code First Programming Model with productivity improvements for Entity Framework 4 (included in .NET 4.0). The Entity Framework CTP5 includes updates to the Code First feature and the simplified API surface (DbContext).

Once downloaded, you can make a reference to the EntityFramework.dll assembly.

Entity Framework "code first" uses a convention where DbContext classes by default look for a connection-string that has the same name as the context class. Because the DbContext class is called "ORMDatabase" it by default looks for a "ORMDatabase" connection-string to use. Above the connection-string is configured to use my local SQL-Server 2008 R2 database (stored within the ORMDatabase folder in the attached zip file). To run the sample application for this article, you just need to install SQL-Server Express 2008 R2 and change the connection string where needed.

Initializing Entity Framework

Entity Framwork Code First enables you to easily connect your POCO model classes to a database by creating an API that is based on the DbContext class that exposes public properties that map to the tables within a database. Initializing the DbContext is as simple as instantiating the ORMDatabase class.

The DbContext class has a member called OnModelCreating, which is useful for code first modeling. Any additional configurations you want to apply to your domain model can be defined in OnModelCreating just before the Entity Framework builds the in-memory metadata based on the domain classes. In the example below, I map the POCO classes to the names of the database tables in SQL-Server.

Now that I have all the plumbing set-up for NHibernate and the Entity Framework, I will want to expand on this sample application and add some complexity to the underlining domain model and move the sample application towards a more real-world solution. The goal of this application will be to exercise the different object relation mapping tools and see how they perform in terms of response time, ease of implementation and overall flexibility and reliability.

Dynamic Paging of Data

This sample application uses MVC 3 as the front-end. It contains a page that allows the user to search and page through customer information. Below are sample methods for creating pagnated data using both NHibernate and the Entity Framework.

As you can see above, both frameworks are able to dynamically build commands to perform a dynamic SQL operation and return a generic list of "paged" customer objects in ascending or descending order - including returning a total count of rows that are available in the database based on the SQL query selected.

NHibernate uses an ISession interface that allows you to use the CreateCriteria object to build a SQL request. NHibernate also allows you to submit mutiple SQL commands to the database at once by using the CreateMultiCriteria object for returning both a recordset of data and returning the row count.

Dynamic LINQ Library

The Entity Framework paging example above uses Dynamic LINQ to SQL. To get this to work, I had to download the Dynamic LINQ Library source code from Microsoft and save it in a C# class file called DynamicLibrary.cs and then reference the namespace System.Linq.Dynamic in my Application Service class.The Dynamic LINQ library implements the IQueryable interface to perform it's operations. This was needed because I needed to be able to pass literal string values into LINQ's Lambda expression syntax.

Instrumentation

In the context of computer programming, instrumentation refers to an ability to monitor or measure the level of a product's performance, to diagnose errors and writing trace information. Instrumentation is in the form of code instructions that monitor specific components in a system.

Through out this sample application I inserted “instrumentation” code to record the response time of each method. Later I can benchmark and compare the performance of each object relational mapper framework. The PerformanceLogging class used throughout this application will measure the performance of each method by executing it’s StartLogging and EndLogging methods. Basically the PerformanceLogging class uses the .NET Environment.TickCount property.

The TickCount is a 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started.

The PerformanceLogging class has functionality where logging can be turned off. A threshold can also be set as a high-water mark for logging the response time in the database. At some point in time when you are in production, you might want to only log slow response times after a given number of seconds has elapsed.

Conclusion

This sample application detailed using the Abstract Factory Design Pattern to help test drive object relational mapping tools such as NHibernate and The Entity Framework from Microsoft. Moving forward I will build upon this application by adding more complexity and additional functionality to exercise these frameworks. NHibernate and The Entity Framework are apples and oranges in the same fruit bowl. NHibernate is an open source project derived from the Java Hibernate project. The Entity Framework is a pure Microsoft product. Both ultimately accomplish the same goals, mapping database objects to domain objects - it's just that they do it in very different ways. In the world of Information Technology we face technology decisions all the time. Fortunately there are design techniques like the Abstract Factory Design Pattern to help us swap out components of our application if needed.

Share

About the Author

Mark Caplin has specialized in Information Technology solutions for 25 years. Specializing in full life-cycle development projects for both enterprise-wide systems and Internet/Intranet based solutions.

For the past ten years or so, Mark has specialized in the Microsoft .NET framework using both C# and VB.NET as his tools of choice.

The downloaded source code didn't contain some assemblies that where obviously referenced by NuGet. Luckily packages.config was still present in the project(s) and showed the expected versions. To restore the assemblies I used the Package Manager Console and this link http://nuget.org/packages/NHibernate/3.0.0.4000[^]After the assemblies where restored I still had a compiler error: ModelBuilder was unknown and had to be changed to DbModelBuilder in order to compile. Probably Visual Studio picked a different version of EF? After this code change everything worked fine. And of course don't forget to attach the mdf-file and change the connectionstring. Perhaps this info is useful if you encounter the same problems. Maybe a new zip-file with with compiler ready code can be posted here?

I have a bit of work still to do. I need to create about 50 tables that will need to be mapped to see how fast themappping of objects will load. I also need to load the tables with a good amount of test dataand include some complex SQL queries. Once all this is done, I then need to find some load testing software that cansimulate about 50 users.

Perhaps I can write a follow-up article with performance measurements when I'm done.