devblog.avesse.net

programming and the web.

Your ORM “Model” is not your Domain Model

There’s been a lot of talk in our company around ORMs and the best data access strategy lately.  As .NET developers, we’ve grown accustomed to using ORM’s (whether it be Linq2Sql, EntityFramework or NHibernate (I assume it applies just as well to non-.NET ORMs)) for our domain model.  Sometimes the ORM classes would be extended and customized, but at the root the ORM “Model” always represented the “Domain Model” of the application.  I’ve even seen a couple of guides saying that an ORM negates the need for a data layer – the ORM is your data layer.

When ORMs went mainstream in the .NET world with the release of Linq2Sql, it completely blew my mind.  I learned later that it was not a new concept, with patterns like ActiveRecord being widely applied in other languages, but it was new to me.  For my whole development career up to that point (admittedly quite short) I had manually mapped relational database queries to their object counterparts using repeated, ugly and cumbersome code.  I clearly remember watching a video by Anders Hejlsberg – the main developer behind C# – around the mismatch of relational data vs classes and objects.  The problem presented was exactly the problem I faced.  The solution presented was perfect.  You can now treat your database rows, with all their related data, as native CLR objects and child objects.  “Mindblowingly awesome” could not describe it.

The benefits of going this route seems endless.  Refactoring becomes easier.  You reduce boring, repetitive boilerplate mapping code.  It’s even, dare I say it, elegant.

Since ORMs became mainstream in the .NET world with the release of Linq2Sql, the pattern of using ORM models (hand-coded POCOs or generated code) as the domain model of an application had become commonplace.  You’d find it in tutorials and guides from reputable websites, and everyone was doing it, so it must be best practice, right?  It was for a while, but with hard experience, issues started to creep in.

The dreaded Select N + 1 problem.

If  the phrase “Select N + 1” is new to you, start here (and keep googling). The main problem with an ORM model is that it gives you the illusion of an always-available hierarchy of objects that you can call at will.  That means you can loop over an object’s child properties, and it’ll just be there, thanks to the lazy-loading capabilities of most ORMs.

Which means, if you don’t consider the ORM when writing domain logic code, you have an ever-increasing number of trips to the database for each child entity, and the result can’t be cached, because the rest of the application depends on having that lazy-loading, get-it-if-I-need-it capability always being there.  The problem compounds when you have child entities numbering in the thousands.

Of course, you can use a LoadWith() method or something similar to specify which child entities should be loaded with the main object to solve this problem to some degree.

Blurring of application layers

But even if your data layer is optimised to load child entities when needed, you still have the unloaded child entities as exposed properties of your ‘main’ entity object, handing the incentive to another developer to load those child entities as needed.  And having to give consideration to these issues at a lower level defeats the purpose of treating your data model as native CLR objects in the first place.

Your ORM model is not your Domain Model

The conclusion I’ve come to is that, except in very simple cases, treating your ORM “model” as your domain model is a fundamentally bad idea.  Your ORM model is a very convenient representation of your database, nothing more.  Sure, you can abstract a little bit using inheritance hierarchies and class extensions, and configure your Repository to load the child entities you might need, but underneath it all, you’re still working with a relational database and SQL queries.   Using an immediate-feedback tool like MiniProfiler to see what goes on in the database makes that uncomfortably obvious.

Of course, chucking out the ORM pattern completely deprives you of many benefits.  An ORM gives you type-safe access to the database with no use of magic strings.  When using a type-safe language such as C#, changing the data model will tell you at compile-time where else you need to make changes.  And it just makes data-access code that much easier to write.

A solution?

So what I’ve started to do with new projects is to treat the ORM as a data-specific layer, similar to how you would treat data consumed from a web service.  There’s a separate layer dealing with the mapping logic, and you never expose the underlying data model.  It creates some extra work, but makes the rest of the application easier to write and more reliable.  It also means that if you decide to use stored procedures or some other custom data access logic code, it’s completely abstracted.

For anything vaguely complex, I find the latter of the following patterns desirable.

ORM-centered Pattern:

(ORM + business logic)  -> (UI/ORM mapping) -> UI

ORM-ignorant pattern:

ORM model -> (ORM/Domain model mapping)  -> Domain model + business logic  -> (UI/Domain model mapping) -> UI

What do you think?

Using a SOAP Extension and Log4Net to trace an ASMX web service

Recently I had to implement some error logging on an old-ish ASMX SOAP web service.  Specifically, I wanted to get the stack trace for errors and the request input that caused them.  I’m told this is quite easy with WCF, but takes a bit of hackery with ASMX.

Initially I wanted to use Elmah because it’s super easy to set up and I use it in all my projects.  Unfortunately, ASP.NET  web services never fire Application_Error, which is where Elmah hooks in.  And I wasn’t going to wrap every method in a try/catch to log errors manually.

To intercept requests and responses as well as errors, you need to write a Soap Extension.  The Soap Extension then writes to the logging tool of your choice.  For this I used Log4Net, mostly because most of the log viewers are built for Log4Net and easy to configure for it (I quite like YALV, but there are many others).  Of course you can also log with Elmah, which I did for errors.

I used the template for a SoapExtension from MSDN and just plugged in the logging code in the appropriate places.  You can attach the SoapExtension by either using an attribute on the web service method you want to log, or you can register it in the web.config to log all requests.  I chose the latter, and configured Log4Net to use the XML Layout, since YALV (which I quite like) displays it nicely.

Get the Log4NetSoapExtension class and configuration here.

Just copy the Log4NetSoapExtension class to your project and add the config settings, and you’ve got a log of every SOAP request and response, as well as stack traces for errors.

Switch to our mobile site