Pleasing the O/R Mapper – Default Constructor Hack

Hack of the day:

Most O/R mapper frameworks require entities to implement a default constructor.

This is most often not a big deal, most entities would support a default constructor no matter if the mapper needed it or not.
However, if you intend to expose an entity that only support a copy constructor.

Let’s say for the sake of the argument that we have an immutable “Order” class, that can only be created by passing an “OrderRequest”:

public class Order
{
   public Order( OrderRequest request )
   {
         this.Customer = request.Customer;
         this.Details =
                  request
                  .Details
                  .Select ( requestDetail => 
                                new OrderDetail (requestDetail))
                  .ToList();
         ...
   }

   ....
}

No matter if the order is only partially or completely immutable, you want to force developers to instantiate the order by the above constructor.

But if the mapper forces you to supply a default constructor, then you can no longer guarantee that the class is used correctly.

So what can be done about it?

I’ve come up with a hack that prevents this problem, but be aware that this is a pure hack ;-)
You can provide a default constructor and mark it with the “Obsolete” attribute.

This can prevent your code from calling the constructor while allowing the mapper framework to create the entities through reflection (which most POCO mappers already do).
You can even separate out this hack code from the actual entity using partial classes:

public partial class Order
{
   public Order( OrderRequest request )
   {
         this.Customer = request.Customer;
         this.Details =
                  request
                  .Details
                  .Select ( requestDetail => 
                                new OrderDetail (requestDetail))
                  .ToList();
         ...
   }

   ....
}

--other file--

public partial class Order
{
     [Obsolete("For NHibernate use only!",true)]
     public Order() {}
}

To keep the hack code away and a safe distance from the actual implementation you could place all those partial default ctor snippets in a separate file or so.

e.g. “NHibernateHack.cs” or something similair.

Also note that for NHibernate, there are other options see: http://nhforge.org/blogs/nhibernate/archive/2008/12/12/entities-behavior-injection.aspx

But this trick is applies to any mapper that creates instances through reflection and requires a default ctor.
Or maybe this is an old trick, but it does fill it’s purpose.

//Roger

2 thoughts on “Pleasing the O/R Mapper – Default Constructor Hack”

  1. Pingback: DotNetShoutout
  2. If you’re using proxies you can also make the constructor protected.

    IMO, persistence mechanisms like NHibernate and Db4o should use the opcode Initobj in IL to instantiate an object while bypassing the constructor. There are some problems with partial trust but otherwise it should be perfectly valid for serialization tools.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s