Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,026 | Comments: 44,842

filter by tags archive

Support dynamic fields with NHibernate and .NET 4.0

time to read 8 min | 1403 words

A common theme in many application is the need to support custom / dynamic fields. In other words, the system admin may decide that the Customer needs to have a few additional fields that aren’t part of the mainline development.

In general, there are a few ways of handling that:

  • DateField1, DateField2, StringField1, StringField2, etc, etc – And heaven helps if you need more than 2 string fields.
  • Entity Attribute Value – store everything in a n EAV model, which basically means that you are going to have tables named: Tables, Rows, Attributes and Values.
  • Dynamically updating the schema.

In general, I would recommend anyone that needs dynamic fields to work with a data storage solution that supports it (like RavenDB Smile, for example). But sometimes you have to use a relational database, and NHibernate has some really sweet solution.

First, let us consider versioning. We are going to move all of the user’s custom fields to its own table. So we will have the Customers table and Customers_Extensions table. That way we are free to modify our own entity however we like it. Next, we want to allow nice syntax both for querying and for using it, even if there is custom code written against our code.

We can do it using the following code:

public class Customer
    private readonly IDictionary attributes = new Hashtable();
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }

    public virtual dynamic Attributes
        get { return new HashtableDynamicObject(attributes);}

Where HashtableDynamicObject is implemented as:

public class HashtableDynamicObject : DynamicObject
    private readonly IDictionary dictionary;

    public HashtableDynamicObject(IDictionary dictionary)
        this.dictionary = dictionary;

    public override bool  TryGetMember(GetMemberBinder binder, out object result)
        result = dictionary[binder.Name];
        return dictionary.Contains(binder.Name);

    public override bool TrySetMember(SetMemberBinder binder, object value)
        dictionary[binder.Name] = value;
        return true;

    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        if (indexes == null)
            throw new ArgumentNullException("indexes");
        if (indexes.Length != 1)
            throw new ArgumentException("Only support a single indexer parameter", "indexes");
        result = dictionary[indexes[0]];
        return dictionary.Contains(indexes[0]);

    public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)

        if (indexes == null)
            throw new ArgumentNullException("indexes");
        if (indexes.Length != 1)
            throw new ArgumentException("Only support a single indexer parameter", "indexes");
        dictionary[indexes[0]] = value;
        return true;

This is fairly basic so far, and not really interesting. We expose a hashtable as the entry point for a dynamic object that exposes all the dynamic fields. The really interesting part happens in the NHibernate mapping:

<class name="Customer"

    <id name="Id">
        <generator class="identity"/>
    <property name="Name" />

    <join table="Customers_Extensions" optional="false">
        <key column="CustomerId"/>
        <dynamic-component name="Attributes" access="field.lowercase">
            <property name="EyeColor" type="System.String"/>

As you can see, we used both a <join/> and a <dynamic-component/> to do the work. We used the <join/> to move the fields to a separate table, and then mapped those fields via a <dynamic-component/>, which is exposed an IDictionary.

Since we want to allow nicer API usage, we don’t expose the IDictionary directly, but rather expose a dynamic object that provides us with a nicer syntax.

The following code:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
        new Customer
            Name = "Ayende",
            Attributes =
                EyeColor = "Brown"

Will produce the following SQL:


And that is quite a nice solution all around Open-mouthed smile



Very nice indeed!


Yeah, thats really cool and easy.

And btw it is good to read some interesting stuff again after a long time... :-)

Andrey Shchekin

I would say using some kind of IUserType (I do not remember if <dynamic-component allows that) to create the HashtableDynamicObject would be better.

Otherwise anyone who refactors the code to virtual dynamic Attributes { get; private set; } will break it, because it is not obvious that this field is used externally.


So, I need to define each of dynamic field in the mapping? I think it is ugly.

Daniel Lang

I think the main advantage of this approach is the huge performance benefit over an EAV model. Unfortunately I don't see a way to get this working in a multi-tenant architecture, where different tenants need to have individual fields, while still using on the same DB.

Boris Drajer

Great stuff, in v3.0 NHibernate has really outgrown the "ORM" moniker and is on its way to becoming a platform.

@hazzik: I believe you could use ConfORM or Fluent NHibernate to do the mapping dynamically.

Frank Quednau

Daniel, I guess supporting different customers with different schemas on the same DB schema will always be an interesting proposition.

Ayende Rahien


Since the data storage in a RDBMS, you really have no choice.


You should use different schemas / databases for different tenants.

Daniel Lang


Whether different databases and schemas for different tenants are a good choice depends on the kind of software. Let's say you have a SaaS - based CRM-application and you want your customers to choose which fields make up a single business-contact. You need to find a way, to dynamically allow to customize the contact-entity.

In such a case it would not only be a waste of memory (each db-instance can take up to hundreds of mb) but also a unnecessary overhead while managing updates, backups, etc.


Would you say that RavenDB would be a good choice in such a situation?


looks nice.. but i don't like it that you need to write in the xml file properties of a dynamic field..

why... because it isn't dynamic any more.. if there is a new field you have to go in the code to add it..

that's why this is better to use it with mongodb because of the json solution. you don't need to use xml..or get in the code for adding a new field

add field detail page on asp.net and it add this field in the document at the monogdb.. you can even search these dynamic fields..

that's the real dynamic..


Ayende Rahien


I guess you missed the part where I recommended doing just that, then...


uuu..? you still using a xml mapper and need to edited the xml file for adding new fields...

i don't see that you are getting a collection from the database..

has only one propertie.. it isn't a collection..

so if i need to add Eyesize i need to put

in it :s....

oke.. you don't need to add it in the .net code.. but you have to edit in backend the xml file.. :S..

Ayende Rahien


I was actually referring to:

In general, I would recommend anyone that needs dynamic fields to work with a data storage solution that supports it (like RavenDB , for example).

But in response to your other questions:

  • You can put a collection in a dynamic property.

  • You can edit the configuration programatically

Jake Scott

Is there any way to combine this with NHibernate Lucene Full text search?


This is great for basic types.But can I add a many to one relation problematically.


How are the newcolumns created in customer_extensions.Is it Nhibernate doing update schema on the database.

Comment preview

Comments have been closed on this topic.


No future posts left, oh my!


  1. Technical observations from my wife (3):
    13 Nov 2015 - Production issues
  2. Production postmortem (13):
    13 Nov 2015 - The case of the “it is slow on that machine (only)”
  3. Speaking (5):
    09 Nov 2015 - Community talk in Kiev, Ukraine–What does it take to be a good developer
  4. Find the bug (5):
    11 Sep 2015 - The concurrent memory buster
  5. Buffer allocation strategies (3):
    09 Sep 2015 - Bad usage patterns
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats