One domain, multiple data sources, and ORM’s

Different representations

Relational data bases and object oriented design are very different representations of a business model. In fact relational database don’t event try to model the business, just store the data related with it.

This two different representations, however, are very related, and that’s because the majority of the systems use a relational database to persist the business model they have represented in an object model. Thus, we are forced to map two different representations of the business and there is were the ORM’s get into the picture.

This is well known as Impedance Mismatch and there’s a lot of documentation and articles about it.

Examples

In case you still have any doubts about the relational database and objects being a different thing let’s check some examples.

The first example is about inheritance and is easy to see the difference between a basic class relation in OOP and a relational store trying to replicate that relation. Which by the way can be done in three different ways.

Inheritance in objects and databases

In the same line is easy to see different implementations of a composite pattern or a tree structure.

Composite pattern in objects and databases

You can find a good article containing several examples here.

Designing

Once we agree that this two technologies are quite different and have basic philosophical differences we must conclude that they should be designed independently, the idea of getting a good design in one model starting from the other is at least questionable. you may get a decent result in a very simple case but that is has far as it gets.

Multiple data sources

A specific case starting with a object oriented model designed independently is that not all your entities lives in the same database, or within the boundaries or the system or even in your own company.

This situation is very common in modern systems that interact with a lot of external services. Following is a very simple example of this that can be presented in any system that uses OAuth or any federated authentication system.

The database representation for that model is very simple. As we don’t have a local representation of the IUser entity in the database all we need is a table to represent MyEntity that has a column to store the IUser.ID in order to get the full IUser entity as needed.

Even though, this is a very simple situation that could be solved in very simple way by writing SQL queries in your code is not simple at all for an ORM.

Solving the problem using ORM’s

We’ll try to solve this problem in .Net using the two major ORM’s, nHibernate and Entity Framework.

nHibernate

Let’s start with nHibernate. In this case the solution is pretty easy. All we need to do is create a IUserType for the IUser interface and that is all.

public class UserMapper : IUserType
{
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
var dataParameter = (IDataParameter)cmd.Parameters[index];

dataParameter.Value = value == null
? (object)DBNull.Value
: ((User)value).Id;
}

public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
var userId = (int?)NHibernateUtil.Int16.Get(rs, "UserId");

return userId.HasValue
? new User { Id = userId.Value }
: null;
}

:
:
:
}

There you go. Now just declare the Owner property type as UserMapper in your mapping and you got it.

Entity Framework

Up to this point we were lucky enough to get around the impedance problem and multiple data sources in a way that’s decently elegant. However, there is not equivalent in Entity Framework for IUserType or something that allows us to solve this problem without braking a premise of the ORM’s, that is, the ORM shouldn’t mess with the model.

Sadly, there is no way to accomplish what we want, without changing the model. At least we get to do this with a private property so the model wont be affected outside our class.

The first think you need to to is to add a back property that will be the one that will be saved to the database.

public class MyEntity
{
[Column]
private int? OwnerId
{
get { return Owner?.Id; }
set { Owner = value.HasValue
? new User { Id = value.Value }; }
: null;
}
}
    public User Owner { get; set; }
}

At this point we only need a way to save the private property to the database. A good solution to do this can be found here, I’ll just move it here for clarification and completeness of this article.

Now let’s start working with the context configuration. As we added a new property that will be mapped to the database column we need to tell EF not to map the Owner property

class MyEntityMap : EntityTypeConfiguration<MyEntity>
{
public MyEntityMap()
{
Ignore(t => t.Owner);
}
}

You will notice that in addition to the private property added we also marked it using the [Column] attribute in order to identity it latter during mapping. A good thing is that CollumnAttribute is a class from System.ComponentModel.DataAnnotations so at least we didn’t have to add a reference to EF in our project model. Now we need to tell EF to store that private property and we are going to do that by adding a new convention. This particular convention is based on the [Column] attribute we just mentioned but it doesn’t need to be that way. You can check this particular convention and create on that’s suits you best than this one.

public sealed class NonPublicColumnAttributeConvention : Convention
{
public NonPublicColumnAttributeConvention()
{
Types().Having(NonPublicProperties)
.Configure((config, properties) =>
{
foreach (PropertyInfo prop in properties)
{
config.Property(prop);
}
});
}

private IEnumerable<PropertyInfo> NonPublicProperties(Type type)
{
var matchingProperties = type.GetProperties(BindingFlags.SetProperty | BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(propInfo => propInfo.GetCustomAttributes(typeof(ColumnAttribute), true).Length > 0)
.ToArray();

return matchingProperties.Length == 0 ? null : matchingProperties;
}
}

The only thing that’s left is to configure the context to use our map and the convention.

public class MainContext : DbContext 
{
public MainContext() : base("default") { }

protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Conventions.Add<NonPublicColumnAttributeConvention>();

builder.Configurations.Add(new ProjectMap());
}
  public DbSet<MyEntity> MyEntities { get; set; }
}

Hopefully we won’t to wait to much to get something more powerful in EF to get this done as it should but this is the best solution I found do far.

Links

User voice

A user voice item asking to get more powerful conversion support

StackOverflow

The original solution to map private properties with EF.