LINQ To SQL / Entity Framework / NHibernate ORM Top-Down, Objects First

People demand freedom of speech as a compensation for the freedom of thought which they seldom use. – Soren Kirkegaard

In the process of stumbling through LINQ To SQL to see if I would be able to represent a SQL Server database schema I created to provide storage for a hierarchical well-defined XML Schema for a commonly used utility object, I came to the realization that I was indeed doing everything completely backwards!

What I am saying is this:  ORM should be done by focusing on the OBJECTS FIRST, not the Database Schema! Unfortunately, most of the tools we have are data-centric, not object-centric.  Scott Allen has a post that clearly describes the debacle.

To my knowledge, there will not be any plain old CLR objects (POCOs) in Entity Framework. LINQ to SQL doesn’t yet have all the mapping capability to really separate the object model from the underlying database schema – and of course, you can use it with SQL Server only.

Now, this situation may improve in the future. But hey -- I need to write this application now, and I’m not about to hold my breath waiting.

Of all the .NET frameworks out there (including the current Microsoft offerings) the only mature offering that appears to be really capable of providing the mapping functionality I need is NHibernate. With NHibernate, I can create my objects (classes) first, create the mapping schema, and then using the SchemaExport class to create the matching database schema. Best of all, NHibernate is happy whether you do this with SQL Server, Oracle, or even SQLite.  Pete Weissbrod has some excellent material that you can use as a study guide on how to do this.

The key feature with an ORM like NHibernate is what's called transparent and automated persistence:

A DataSet allows you to extract the changes performed on it in order to persist them. NHibernate provides a different feature: It can automatically persist your changes in a way that is transparent to your domain model. This means a complete separation of concerns between the persistent classes of the domain model and the persistence logic itself, such that the persistent classes are unaware of—and have no dependency to—the persistence mechanism.

An “Item” class, for example, will not have any code-level dependency to any NHibernate API.  It doesn’t need funky attributes on the class or methods that can make serialization and re-use over the wire via WCF difficult. In addition,  NHibernate doesn’t require that any special base classes or interfaces be inherited or implemented by persistent classes, nor are any special classes used to implement properties or associations.

The bottom line for me is that in a system with transparent persistence, objects aren’t aware of the underlying data store; they need not even be aware that they are being persisted or retrieved. They can be serialized, sent over the wire, used for NUnit Tests, and more.

As Scott indicates in his post, developers need to learn how ORM identity maps work. Think objects first, data second. Start with your classes and business logic, and only then get the persistence and mapping to the database done. It was a hard lesson to learn because I’ve wasted a lot of time, partly because of a predilection for using the Microsoft flavor,  but now I think I can safely say that “I got it”.

Comments

  1. Anonymous2:07 AM

    Nice post! Personally I find NHibernate really bloated and too much - for smaller applications it's too complicated and bulky, for bigger, complex ones, it's far superior to have DB experts do the queries (SPs, optimized SQLs etc.) and use simple utility classes as frontend no matter if the objects are created first, or the model already is defined in the DB.

    I've seen to many developers use NHibernate with too little knowledge of the framework. None of them had the time (or interest?) to really, really learn NHibernate, which almost always ended in non-optimized solutions (it's VERY easy to get things wrong in NHibernate!). So, IMHO, to use NHibernate you really need to dedicate time to learn it well, and you better believe this is the right thing for me/us.

    ReplyDelete
  2. Anonymous4:10 PM

    "objects aren’t aware of the underlying data store; they need not even be aware that they are being persisted or retrieved"

    keep in mind that while you can retrieve pretty much anything in a very transparent manner, it's not a good idea to always do so. While NHibernate's lazy loading features are _very_ nice, misusing them can lead to very inefficient database acces.

    Be sure to use the power of NHibernate's Criteria API to construct efficient queries for more efficient data fetching.

    Also, while it is possible to serialize NHibernate's objects to send them over the wire, you often need to pull out a bag of tricks if you want objects with lazy loading (which are actually dynamically generated proxy instances) to go over the wire (and back again) without problems. I actually keep my NHibernate entities completely behind my service layer and only send DTO's over the wire.

    Btw, don't take this as criticism of NHibernate. I'm actually a very happy NHibernate user, and also contribute to the NHibernate project :)

    ReplyDelete
  3. I agree w/ the original post, after fiddling w/ linq to sql, thinking i'm looking at an ORM solution, i found that really i'm found an abstraction of my database. Close but no cigar. I still have to do all my mapping manually, if i'm not instersted in using the objects directly modelled by the database's scheme, which it turns out i really don't. I guess if i were binding directly to my presentation layer, and was bereft of concepts like DDD, i'd feel really happy w/ my heavily coupled single layer applicaiton...

    ReplyDelete

Post a Comment

Popular posts from this blog

Some observations on Script Callbacks, "AJAX", "ATLAS" "AHAB" and where it's all going.

IE7 - Vista: "Internet Explorer has stopped Working"

FIREFOX / IE Word-Wrap, Word-Break, TABLES FIX

System.Web.Caching.Cache, HttpRuntime.Cache, and IIS Recycles

FIX: Requested Registry Access is not allowed (Visual Studio 2008)