A long time before Entity Framework (EF) Core was around – or any other Entity Framework for that matter – we already had NHibernate. In this article, I’m going to talk a bit about EF and NHibernate, what approaches and differentiates them.
NHibernate is a port of Hibernate from Java, one of the oldest and most respected Object-Relational Mappers (ORMs). It has existed since 2003 and recently has been developed entirely by the community, without any sponsor or umbrella company. It has always been open source under GNU Lesser General Public License.
Entity Framework Core is the .NET Core version of Microsoft’s flagship product that was first released in 2008. In the beginning, it was part of .NET 3.5 SP1 and as such it was licensed to be used for free, but no source code was available. As part of the .NET Core initiative, it was totally rebuilt now targeting .NET Core, and as part of .NET Core, it was made available under the MIT License. Since the beginning, it was closely linked to .NET and Visual Studio versions.
NHibernate has had a couple of versions:
- Version 1 was the original one and offered basic features; initially it didn’t support generics, but those were introduced in a later minor version; it ran on .NET 1.1.
- Version 2 dropped support for .NET 1.x.
- Version 3 introduced LINQ (.NET Language-Integrated Query) and QueryOver, and also lazy loading of properties.
- Version 3.2 and 3.3 introduced fluent (loquacious) configuration and conventions, mapping of views, HQL (Hibernate Query Language) improvements, and integrated bytecode generator.
- Version 4 started targeting .NET 4 and BCL (Base Class Library) sets, instead of Iesi.Collections. Now using Roslyn (.NET Compiler Platform).
- Version 5 added asynchronous programming, fixed TransactionScope support, and a lot of cleaning, including removing obsolete code.
- Version 5.1 brought .NET Core support
As for Entity Framework (EF):
- Version 1 had basic functionality with model-first and database-first workflows, and was released with .NET 3.5 Service Pack 1.
- Version 4 came with .NET 4 and supported lazy loading, self-tracking entities, POCOs (Plain Old CLR Objects), and generator templates (T4 – Text Template Transformation Toolkit).
- Versions 4.1 and 4.3 (“Code First”) introduced the code-first development model and a much cleaner API; it was the first to be distributed out of bound through NuGet. 4.3 introduced migrations.
- Version 5 brought enumerated types, spatial types, and table-valued function support.
- Version 6 added interceptors, logging, asynchronous operations, custom conventions, and support of stored procedures for CRUD operations.
- .NET Core 1 was a total rewrite, and as such it didn’t offer all features as the previous versions. Only basic functionality, plus the architecture to support non-relational databases. Still added interesting features such as shadow properties.
- .NET Core 1.1 brought mapping to fields, explicit loading, connection resiliency, and some previously available APIs.
- .NET Core 2 introduced owned entities, global filters, the LIKE operator, DbContext pooling, explicitly compiled queries, scalar function mappings,nd self-contained entity configuration classes.
You can see that Microsoft hasn’t been exactly idle, and a lot has happened since the release of EF 1. In fact, the EF Core family is almost totally unrelated to the original one, and even Code-First was totally new, even though the original version was still underneath it.
NHibernate now supports .NET 4 and higher running on Windows or platforms where Mono is available and as of version 5.1 (released a couple days ago) it also supports .NET Core. There are no plans to have it support data sources other than relational databases.
EF Core runs on .NET Core, and therefore on any platform that supports it. It is based on a provider model that theoretically can work with any kind of data source, not just relational ones. Work is in progress for Azure Cosmos DB, and others are likely to follow.
NHibernate is distributed through NuGet as a single DLL, with no other dependencies unless we need ordered sets, where we also need Iesi.Collections. Everything is built in. It needs the full .NET Framework, or .NET Core.
Entity Framework Core, on the other hand, consists of multiple DLLs, coming in many NuGet packages. The good thing is, NuGet dependencies are brought along as needed, so, for SQL Server, you only need to grab Microsoft.EntityFrameworkCore.SqlServer. Targets .NET Core, of course.
Internally, they are both quite extensible, with lots of moving parts, some of which can be replaced.
Entity Framework Core builds upon .NET Core facilities like logging and dependency injection, and it leverages those for modifying internal components. Pretty much anything can be switched.
NHibernate does not use dependency injection and the way to replace each service is quite different from service to service. Overall, it’s not as extensible as EF Core.
In NHibernate, we need do instantiate a Configuration object, and from it produce a Session Factory. There should be only one of them at a time in an application, as they are relatively “heavy”. From a Session Factory, we produce Sessions, which are lightweight abstractions encapsulating an ADO.NET connection. Everything stems from it.
With EF, we only need to worry about a DB Context; it includes all the mapping and configuration information, and exposes all APIs for interacting with the datasource. It’s a much simpler model, but one can argue that the separation of concerns in NHibernate is more efficient.
Out of the box, NHibernate supports more than 10 different databases and versions, including:
- SQL Server (including Azure)
- SQL Server CE
- Oracle Database (several editions)
- Any using ODBC (Open Database Connectivity), or OLE (Object Linking and Embedding) DB
Microsoft only makes available providers for:
- SQL Server (including Azure)
The in-memory provider is particularly useful for unit testing scenarios. Work is in progress for Cosmos DB (Document DB) and Oracle Database. Other vendors already make available providers to other databases, for free or commercially.
It is clear that NHibernate has advantage here, as it’s much easier to start working on any supported database.
Entity Framework Core uses fluent (code-based) configuration and fluent or attribute-based mappings. Built-in conventions cannot be replaced or added to, at this moment.
NHibernate has both XML and fluent configuration and mappings. It also offers attribute mappings through the NHibernate Attributes companion project. Custom conventions are very powerful in NHibernate, EF Core still doesn’t have them, and this is something that NHibernate is better at, right now.
Both of them need mappings, in any form. Both can map non-public members, properties or fields. Also both have the notion of value types (owned entities in EF, components in NHibernate). NHibernate can map a property or field to a custom SQL command.
Also, both support shadow properties, that is, entities that are part of the database schema, but not mapped into the class model. With EF Core, we can even query them.
NHibernate fully supports the three “canonical” table inheritance patterns:
- Table Per Class Hierarchy / Single Table Inheritance
- Table Per Class / Class Table Inheritance
- Table Per Concrete Class / Concrete Table Inheritance
EF Core can only live with Table Per Class Hierarchy / Single Table Inheritance. There’s an open ticket for fixing it, but it’s not on the roadmap.
Where primary keys are concerned, Entity Framework Core supports:
- IDENTITY auto-generated keys on SQL Server and SQLite
- Sequences on SQL Server 2012+
- Manually assigned values
NHibernate, on the other hand, offers a much richer set, including:
- Identities in SQL Server/Sybase, or auto-increment values in other databases
- Sequences in any database that supports them
- The database-independent High-Low algorithm
- High-Low based on a sequence
- A generator based on the current time
- Several flavors of GUIDs (Globally Unique Identifiers)
- Manually assigned
EF Core only has LINQ and SQL to query. No strongly-typed inserts, deletes or updates. Still no support for grouping on the database side, it will be fixed in the next version. No projections to non-entity types.
NHibernate, on the other hand, offers:
- Criteria API (a Query Object pattern implementation)
- QueryOver (Criteria with LINQ)
- HQL (object-oriented SQL)
All of these support pagination, as EF Core LINQ does.
It is also possible to do updates, deletes or inserts on top of LINQ queries, which is quite nice. Also, HQL is a great language for querying the database in an agnostic way; it is similar to SQL and can even update, insert or delete entries. NHibernate can project to any class, not just anonymous types.
NHibernate can use stored procedures or custom SQL for any kind of operation. EF Core still lacks this, which was present in pre-Core versions.
NHibernate has futures, which means that multiple queries can be queued, executed on the database, and retrieved at the same time, for databases that support it (SQL Server, Oracle). Also, depending on the primary key generation strategy, one can also batch insert multiple records at the same time.
Both support asynchronous queries and modifications.
Besides transactions, which are supported by all relational databases and major ORMs, some of these offer optimistic concurrency capabilities.
EF Core can use a ROWVERSION/TIMESTAMP column on SQL Server, or any of a list of columns, when updating a record.
NHibernate offers richer capabilities, besides SQL Server ROWVERSION/TIMESTAMP, it can also use database native mechanisms such as Oracle’s ORA_ROWSCN, but also timestamp or version columns. It can also compare all modified columns.
EF Core still does not support ambient transactions (TransactionScope), but the next version will fix that. NHibernate has historically had problems with TransactionScope, but they appear to be fixed now.
EF Core cannot explicitly lock records, but NHibernate does offer an API for it.
Collections in EF Core are simple: just lists, which means, one-to-many. There is no support for many-to-many yet.
In NHibernate, we have:
- Bags of entities: unordered collections with possible duplication
- Sets of entities: no duplication, maybe ordered
- Lists: collections indexed by a number
- Maps: collections indexed by any column or possibly other entity
- Arrays of primitive types
- Collections of primitive or value types (components in NHibernate)
So, as you can see, there’s a lot more going on in NHibernate, it’s not just saying that we have a collection. Both one-to-many and many-to-many associations are supported.
Current version of EF Core (2.0) does not have lazy loading, only explicit (using the API) or eager loading (when doing a LINQ query) of associated entities and collections. The next version (2.1) will introduce this.
NHibernate has lazy loading of associated entities, collections, and even single properties (for large amounts of data, think BLOBs or CLOBs). There’s also explicit and eager loading, these behave the same way as in EF Core.
NHibernate can convert and query any type; EF Core still lacks this capacity, which should be introduced in the next version. With NHibernate, you can already query spatial types, for example.
Both of them have global filters at entity level. NHibernate also offers filtering at collection level, and it’s parameterizable. Easy to do soft deletes or multi-tenancy.
EF Core, as of now, only has basic SQL interception capabilities using the DiagnosticSource functionality. It’s easy to modify the context to do basic tasks before saving, updating, or deleting records. Future versions will offer LINQ expression interception and lifetime events.
NHibernate has a very rich event and interception model. Multiple interceptors can be added, at multiple levels (before/after transaction flush, deleting, inserting, or modifying, and after instantiating, etc).
Both offer first-level caching of entities. NHibernate goes one step further, and has second-level caching using a distributed cache provider, such as these:
- ASP.NET cache
- AppFabric Caching
NHibernate can do validation using the companion project NHibernate Validator, or by implementing an interface (this one has become somewhat legacy).
EF Core uses Data Annotations validation, which is the de facto standard for doing validations in .NET.
NHibernate can do basic database generation and schema update – automatic or upon request.
EF Core has the migrations API, which is quite interesting. This is one aspect where EF is quite ahead of NHibernate, even though there have been attempts to create a similar framework for it. You can list all the versions of a schema, apply one explicitly or go back to a previous version.
As EF Core is quite new, there is not much tooling in Visual Studio for it. It should come with time, of course. There are some third-party products such as Erik Ejlskov Jensen‘s excellent EF Core Power Tools, and maybe a few more. EF can generate entities from the database, and you can even modify the default behavior by registering your own version of infrastructure services.
With NHibernate, there are a few commercial ones, such as LLBLGen Pro or Entity Developer, and also some open-source projects. It doesn’t include any functionality that allows you to generate entities or mappings whatsoever.
NHibernate has so many features that it is easy to forget about one. It is said that its performance is lower than EF’s, and that may be true, but in my perspective performance should not be a driving reason to choose an ORM. With NHibernate, one can map pretty much any database, so there is always an option.
EF Core is very easy to use, generally well documented, and this is something where NHibernate is far behind. As of now, it can only be used in relatively simple scenarios – just consider the lack of support for table inheritance strategies. Having a .NET Core version is essential to me. Having the possibility of supporting non-relational databases using the same familiar APIs and concepts is something very appealing to me, but yet to see working.
EF Core does have a roadmap, which is a good thing. Considering all the effort Microsoft is putting into it – plus the added contribution of the developer community – we can expect the best out of it. Initial versions were discarded by most developers because they lacked many important features and SQL generation was far from optimal, but we’re getting there. New releases seem to be coming at a steady pace, and we can take part in the decision process, even though Microsoft has the final word.
For NHibernate, things are a bit worse. Currently the project is maintained by only a handful of developers, at most. Things do seem to be moving, after some years of stagnation, and a good example is the port to .NET Core. However, without professional developers working full time on this, it is reasonable to assume that progress will not be as fast as with EF – but NHibernate has the lead, in my opinion. The decision process is not so transparent, from where I sit.
- What’s New in .NET Core 2.1 - July 10, 2018
- The Evolution of C#: What’s Changed and What’s Ahead - May 3, 2018
- A Recap from Microsoft’s Most Valuable Professional (MVP) Global Summit - April 4, 2018
- Entity Framework Core and NHibernate: Understand the Similarities and Differences - March 21, 2018
- Visual Studio versus Rider - March 12, 2018