Fluent NHibernate & HasOne(): how to implement a one-to-one relationship

20 Jan 2010

For a (very) long time I've been googling, binging, stackoverflowing, [your-search-engine]ing for a simple yet complete example showing how to implement a one-to-one relationship using Fluent NHibernate.

Fluent NHibernate and lambda expressions as data

If you don't already know, Fluent NHibernate is a fantastic open-source library to be used in conjunction with NHibernate, a powerful O/RM library for .NET. NHibernate works by reading a (usually) manually created XML file that represents the mapping between the Object Oriented and Relational models. There are obvious annoying problems related to the fact of using this XML file, such as not being refactoring-friendly.

Fluent NHibernate is based on the power and expressiviness of lambda expressions to allow for a concise, strongly-type, refactoring-friendly mappings, that eliminates the need of hand-crafted XML files.

It is a very nice example of a somewhat modern pattern, borrowed from functional programming, now possible in C#: using lambda expressions as data. For more details about such emerging patterns, I strongly recommend you this excelent article on MSDN Magazine.

The problem is that I've not yet found an example that fits my needs, and Fluent NHibernate's documentation is somewhat scarce (a big drawback of Fluent NHibernate, I'd say, specially when using it inside a company). What you will most certainly find is people telling you that you might actually need a many-to-one relationship. No, I was needing a one-to-one relationship, I swear, and couldn't find a single example on how to correctly implement it with NHibernate and Fluent NHibernate. Note that I have almost no experience with NHibernate without Fluent NHibernate. I've never created an XML mapping that was more complex than almost-trivial. Had I had some more experience with it, I might had been able to solve this problem more easily.

So I present here a scenario, similar to the one I was facing, involving a one-to-one relationship and how I managed to implement it with Fluent NHibernate.

The scenario

Let's say you have a project that deals with Clients. You normally would have a class to represent this entity, such as:

Model

public class Client {
  protected virtual int Id { get; set; }
  public virtual string Name { get; set; }
  /* ... */
}

(note that the protected id and the virtual modifiers are there to please NHibernate; it creates a proxy class around your model class, so it needs to be able to override getters and setters)

Using Fluent NHibernate, you need no XML file to manage the mappings, all you need is this:

using FluentNHibernate.Mapping;
public class ClientMap : ClassMap {
  Id(x => x.Id);
  Map(x => x.Name);
  /* ... */
}

And that's it! Should you need to refactor Name and call it, say, FullName, the mapping would be automatically updated accordingly (given that you use any minimally-competent refactoring tool).

Here is the corresponding database (the names are slightly modified, not following the standard Fluent NHibernate convention):

Database

Adding some relationships

With NHibernate you are free to model your domain in the object-oriented world, with all the kinds of relationships you might want, and it will take care of the database for you.

One such relationship is a many-to-one relationship. Let's say you want to possibly classify your clients according to some Profiles. A client may have one profile, or no profile at all (if you have not yet decided what is his profile). You would have something like this:

Model

public class Client {
  /* ... */
  public virtual Profile Profile { get; private set; }
  /* ... */
}
public class Profile {
  protected virtual int Id { get; set; }
  public virtual string ProfileName { get; private set; }
  /* ... */
}

The mappings would be:



public class ProfileMap : ClassMap {
  Id(x => x.Id);
  Map(x => x.ProfileName);
  /* ... */
}
public class ClientMap : ClassMap {
  /* ... */
  References(x => x.Profile);
  /* ... */
}

And this is the database, as expected:

Database

And that's all. Should you want, Fluent NHibernate can automatically generate the database for you as well, with one extra line of code on the configuration of the connection to the database.

Simple, huh?

The problem - a one-to-one relationship

Now suppose you have your system running, in production. Everything is fine, not too many bugs (and the ones found not too scary), the business (that partly relies on your software) is running OK.

One day, your boss calls you and (as you can expect) tells you he needs a new feature. Let's say he needs to gather some more details about clients, about their alimentary habits.

You, as the developer, decide that you shall not modify the whole Client class, adding many alimentary properties to it. You'd rather create a new class AlimentaryHabits. However this data is still part of the client, you just decide to separate the classes not to burden the client.

The same argument applies to the database: you want to create a separate table not to burden the Clients table. Should you want to have two classes but only one table, you can create your mappings using Component(), but I won't discuss this here since it is already well documented elsewhere.

What we want in the database is two tables, a Clients with its primary key Id, and a AlimentaryHabits table, with a primary key ClientId that is also a foreign key, referring to Client's primary key:

Database

What you would like to have is a model that looks like this:

Model

#!csharp
public class Client {
  /* ... */
  public virtual AlimentaryHabits AlimentaryHabits
    { get; private set; }
  /* ... */
}
public class AlimentaryHabits {
  public virtual bool LikesPasta { get; set; }
  public virtual bool LikesPizza { get; set; }
  public virtual int AverageDailyCalories { get; set; }
}

This is what we would like to have. But it is not that easy. No. To please NHibernate and allow Fluent NHibernate to correctly create our mappings, we need to change things a bit. And this is my problem, I couldn't find any example on how to implement this mapping.

The solution

To implement this model and the corresponding fluent mapping, we need to modify things a bit. This is the domain:

Model

public class AlimentaryHabits {
  private int ClientId { get; set; }
  private Client Client { get; set; }

  protected AlimentaryHabits() { }

  public AlimentaryHabits(Client client) {
      Client = client;
  }
    
  public virtual bool LikesPasta { get; set; }
  public virtual bool LikesPizza { get; set; }
  public virtual int AverageDailyCalories { get; set; }
}

We need two things to satisfy our OR/M solution:

  • an id of the same type as the main class; and
  • a reference to the main object;

This reference would represent a bidirectional relationship, although we wanted a unidirectional one (you could want something different for your domain). However we could make it private, and it is not even used inside the class, it's just used by NHibernate. Also, note that now we have two constructors. The public constructor, taking a Client parameter, is the one you will use in your code whenever you want to assign a client some alimentary habits, such as: AlimentaryHabits = new AlimentaryHabits(this);. The protected constructor is used internally by NHibernate, and must be present. You can completely ignore it.

This is the corresponding mapping:

public class AlimentaryHabitsMap : ClassMap
{
  Id(Reveal.Property("ClientId"))
    .GeneratedBy.Foreign("Client");

  HasOne(
    Reveal.Property("Client"))
      .Constrained()
      .ForeignKey();

  Map(x => x.LikesPasta);
  Map(x => x.LikesPizza);
  Map(x => x.AverageDailyCalories);
}
public class ClientMap : ClassMap {
  /* ... */
  HasOne(x => x.AlimentaryHabits)
    .Cascade.All();
  /* ... */
}

(the Reveal.Property thing is because both ClientId and Client properties are private, and thus not accessible from the mapping class; they will be accessed through reflection by NHibernate)

This model setup, along with this mapping, will create almost the model we initially wanted to, and the exact database representation we wanted!

Conclusion

This involved more effort than I initially thought it would, but now I have a neat solution. And the next time I will need this, it will be easy to implement, following this directions.

If you know a way to simplify this further, or if you like it, or if you have any questions, leave a comment, I'd be glad to further improve this article!

Good luck!