Introduction
NHibernate and Entity Framework are two of the
most popular O/RM frameworks on the .NET world. Although they share
some functionality, there are some aspects on which they are quite
different. This post will describe this differences and will hopefully
help you get started with the one you know less. Mind you, this is a
personal selection of features to compare, it is by no way an exhaustive
list.
History
First, a bit of history. NHibernate is
an open-source project that was first ported from Java’s venerable
Hibernate framework, one of the first O/RM frameworks, but nowadays it
is not tied to it, for example, it has .NET specific features, and has
evolved in different ways from those of its Java counterpart. Current
version is 3.3, with 3.4 on the horizon. It currently targets .NET 3.5,
but can be used as well in .NET 4, it only makes no use of any of its
specific functionality. You can find its home page at
NHForge.
Entity
Framework 1 came out with .NET 3.5 and is now on its second major
version, despite being version 4. Code First sits on top of it and but
came separately and will also continue to be released out of line with
major .NET distributions. It is currently on version 4.3.1 and version 5
will be released together with .NET Framework 4.5. All versions will
target the current version of .NET, at the time of their release. Its
home location is located at
MSDN.
Architecture
In NHibernate, there is a separation between the
Unit of Work and the configuration and model instances. You start off by creating a
Configuration
object, where you specify all global NHibernate settings such as the
database and dialect to use, the batch sizes, the mappings, etc, then
you build an
ISessionFactory from it. The
ISessionFactory holds model and metadata that is tied to a particular database and to the settings that came from the
Configuration object, and, there will typically be only one instance of each in a process. Finally, you create instances of
ISession from the
ISessionFactory, which is the NHibernate representation of the
Unit of Work and
Identity Map.
This is a lightweight object, it basically opens and closes a database
connection as required and keeps track of the entities associated with
it.
ISession objects are cheap to create and dispose, because all of the model complexity is stored in the
ISessionFactory and
Configuration objects.
As for Entity Framework, the
ObjectContext/
DbContext
holds the configuration, model and acts as the Unit of Work, holding
references to all of the known entity instances. This class is therefore
not lightweight as its NHibernate counterpart and it is not uncommon to
see examples where an instance is cached on a field.
Mappings
Both NHibernate and Entity Framework (Code First) support the use of
POCOs to represent entities, no base classes are required (or even possible, in the case of NHibernate).
As for mapping to and from the database, NHibernate supports three types of mappings:
- XML-based,
which have the advantage of not tying the entity classes to a
particular O/RM; the XML files can be deployed as files on the file
system or as embedded resources in an assembly;
- Attribute-based,
for keeping both the entities and database details on the same place at
the expense of polluting the entity classes with NHibernate-specific
attributes;
- Strongly-typed code-based, which allows dynamic
creation of the model and strongly typing it, so that if, for example, a
property name changes, the mapping will also be updated.
Entity Framework can use:
- Attribute-based (although attributes cannot express all of the available possibilities – for example, cascading);
- Strongly-typed code mappings.
Database Support
With NHibernate you can use mostly any database you want, including:
- SQL Server;
- SQL Server Compact;
- SQL Server Azure;
- Oracle;
- DB2;
- PostgreSQL;
- MySQL;
- Sybase Adaptive Server/SQL Anywhere;
- Firebird;
- SQLLite;
- Informix;
- Any through OLE DB;
- Any through ODBC.
Out
of the box, Entity Framework only supports SQL Server, but a number of
providers exist, both free and commercial, for some of the most used
databases, such as
Oracle and
MySQL. See a list
here.
Inheritance Strategies
Both NHibernate and Entity Framework support the three canonical inheritance strategies: Table Per Type Hierarchy (
Single Table Inheritance), Table Per Type (
Class Table Inheritance) and Table Per Concrete Type (
Concrete Table Inheritance).
Associations
Regarding
associations, both support one to one, one to many and many to many.
However, NHibernate offers far more collection types:
- Bags of entities or values: unordered, possibly with duplicates;
- Lists of entities or values: ordered, indexed by a number column;
- Maps of entities or values: indexed by either an entity or any value;
- Sets of entities or values: unordered, no duplicates;
- Arrays of entities or values: indexed, immutable.
Querying
NHibernate exposes several querying APIs:
- LINQ is probably the most used nowadays, and really does not need to be introduced;
- Hibernate
Query Language (HQL) is a database-agnostic, object-oriented SQL-alike
language that exists since NHibernate’s creation and still offers the
most advanced querying possibilities; well suited for dynamic queries,
even if using string concatenation;
- Criteria API is an implementation of the Query Object
pattern where you create a semi-abstract conceptual representation of
the query you wish to execute by means of a class model; also a good
choice for dynamic querying;
- Query Over offers a similar
API to Criteria, but using strongly-typed LINQ expressions instead of
strings; for this, although more refactor-friendlier that Criteria, it
is also less suited for dynamic queries;
- SQL, including stored procedures, can also be used;
- Integration with Lucene.NET indexer is available.
As for Entity Framework:
- LINQ to Entities is fully supported, and its implementation is considered very complete; it is the API of choice for most developers;
- Entity-SQL, HQL’s counterpart, is also an object-oriented, database-independent querying language that can be used for dynamic queries;
- SQL, of course, is also supported.
Caching
Both
NHibernate and Entity Framework, of course, feature first-level cache.
NHibernate also supports a second-level cache, that can be used among
multiple
ISessionFactorys, even in different processes/machines:
Out of the box, Entity Framework does not have any second-level cache mechanism, however, there are some public
samples that show how we can add this.
ID Generators
NHibernate supports different ID generation strategies, coming from the database and otherwise:
- Identity (for SQL Server, MySQL, and databases who support identity columns);
- Sequence (for Oracle, PostgreSQL, and others who support sequences);
- Trigger-based;
- HiLo;
- Sequence HiLo (for databases that support sequences);
- Several GUID flavors, both in GUID as well as in string format;
- Increment (for single-user uses);
- Assigned (must know what you’re doing);
- Sequence-style (either uses an actual sequence or a single-column table);
- Table of ids;
- Pooled (similar to HiLo but stores high values in a table);
- Native (uses whatever mechanism the current database supports, identity or sequence).
Entity Framework only supports:
- Identity generation;
- GUIDs;
- Assigned values.
Properties
NHibernate
supports properties of entity types (one to one or many to one),
collections (one to many or many to many) as well as scalars and
enumerations. It offers a mechanism for having complex property types
generated from the database, which even include support for querying. It
also supports properties originated from SQL formulas.
Entity Framework only supports scalars, entity types and collections. Enumerations support will come in the next version.
Events and Interception
NHibernate
has a very rich event model, that exposes more than 20 events, either
for synchronous pre-execution or asynchronous post-execution, including:
- Pre/Post-Load;
- Pre/Post-Delete;
- Pre/Post-Insert;
- Pre/Post-Update;
- Pre/Post-Flush.
It also features interception of class instancing and SQL generation.
As for Entity Framework, only two events exist:
Tracking Changes
For
NHibernate as well as Entity Framework, all changes are tracked by
their respective Unit of Work implementation. Entities can be attached
and detached to it, Entity Framework does, however, also support
self-tracking entities.
Optimistic Concurrency Control
NHibernate supports all of the imaginable scenarios:
- SQL Server’s ROWVERSION;
- Oracle’s ORA_ROWSCN;
- A column containing date and time;
- A column containing a version number;
- All/dirty columns comparison.
Entity Framework is more focused on Entity Framework, so it only supports:
- SQL Server’s ROWVERSION;
- Comparing all/some columns.
Batching
NHibernate
has full support for insertion batching, but only if the ID generator
in use is not database-based (for example, it cannot be used with
Identity), whereas Entity Framework has no batching at all.
Cascading
Both
support cascading for collections and associations: when an entity is
deleted, their conceptual children are also deleted. NHibernate also
offers the possibility to set the foreign key column on children to
NULL instead of removing them.
Flushing Changes
NHibernate’s
ISession has a
FlushMode property that can have the following values:
- Auto:
changes are sent to the database when necessary, for example, if there
are dirty instances of an entity type, and a query is performed against
this entity type, or if the ISession is being disposed;
- Commit: changes are sent when committing the current transaction;
- Never: changes are only sent when explicitly calling Flush().
As for Entity Framework, changes have to be explicitly sent through a call to
AcceptAllChanges()/
SaveChanges().
Lazy Loading
NHibernate supports lazy loading for
- Associated entities (one to one, many to one);
- Collections (one to many, many to many);
- Scalar properties (thing of BLOBs or CLOBs).
Entity Framework only supports lazy loading for:
- Associated entities;
- Collections.
Generating and Updating the Database
Both NHibernate and Entity Framework Code First (with the
Migrations API) allow creating the database model from the mapping and updating it if the mapping changes.
Extensibility
As
you can guess, NHibernate is far more extensible than Entity Framework.
Basically, everything can be extended, from ID generation, to LINQ to
SQL transformation, HQL native SQL support, custom column types, custom
association collections, SQL generation, supported databases, etc. With
Entity Framework your options are more limited, at least, because
practically no information exists as to what can be extended/changed. It
features a provider model that can be extended to support any database.
Integration With Other Microsoft APIs and Tools
When
it comes to integration with Microsoft technologies, it will come as no
surprise that Entity Framework offers the best support. For example,
the following technologies are fully supported:
Documentation
This
is another point where Entity Framework is superior: NHibernate lacks,
for starters, an up to date API reference synchronized with its current
version. It does have a community mailing list, blogs and wikis,
although not much used. Entity Framework has a number of resources on
MSDN and, of course, several forums and discussion groups exist.
Conclusion
Like
I said, this is a personal list. I may come as a surprise to some that
Entity Framework is so behind NHibernate in so many aspects, but it is
true that NHibernate is much older and, due to its open-source nature,
is not tied to product-specific timeframes and can thus evolve much more
rapidly. I do like both, and I chose whichever is best for the job I
have at hands. I am looking forward to the changes in EF5 which will add
significant value to an already interesting product.