NHibernate 3.2 Mapping Entities and Value Objects by Code

One of the major new features of NHibernate 3.2 is Mapping by Code, this is one of the features I waited for long time ago, I don’t like mapping by xml files, it is not strongly typed, error prone, and not programmer friendly.

Most of developers like me who prefer mapping by code used to use FluentNhibernate to map their classes by code.

In this post I will introduce the initial domain model of the sample application SellAndBuy and how it is mapped using the new mapping by code feature of NHibernate 3.2.

The Model:

The model consists of five main entities:

  • Customer: A very simple entity describing a customer, has no associations or any complex constructs.
  • Item: An item entity description to describe item to be advertised for, the item is associated to a category as a many to one association. The item can contain one or more pictures through the association to a set of PictureInfo value object through the base class PicturableBase.
  • ItemCategory: Category entity describes the category of the item, a category contains a set of available conditions as a one to many aggregation.
  • ItemCondition: A value object describing a condition (New, Good, Broken, …).
  • Ad: A relatively complex entity describing the ad transaction, it is associated to a customer as many to one association, associated to an item as many to one association, and associated to a condition value object describing the item’s condition. The ad can contain one or more pictures through the association to a set of PictureInfo value object through the base class PicturableBase.
Now to the mapping code:

To map any entity you need to create a class that inherits from ClassMapping<T> and define the mapping behavior in the constructor as method calls with lambda expression parameters.

Lazy() method sets the lazy loading behavior.

Id() method defines the key of the table.

Property() method defines a property mapping to database field.

ManyToOne() method defines association to an entity with many to one cardinality.

Bag() method defines a collection of objects.

Component() is used to map a grouping of fields that is not an entity, it is very suitable for mapping value objects as they don’t have identity and they are immutable.

The following are mappings of the sample domain model.

  • CustomerMap:
    public class CustomerMap : ClassMapping<Customer>
    {
        public CustomerMap()
        {
            Lazy(false);
            Id(x => x.ID, map => map.Generator(Generators.HighLow,
                          gmap => gmap.Params(new {max_low = 100})));
            Property(x => x.FirstName, map => map.NotNullable(true));
            Property(x => x.LastName, map => map.NotNullable(true));
            Property(x => x.Email, map =>
                                       {
                                           map.Unique(true);
                                           map.Length(50);
                                           map.NotNullable(true);
                                       });
        }
    }

This mapping code first mark the class as non-lazy loaded, define the int Id field with a generation strategy, defines three properties.

  • ItemMap:
    public class ItemMap : ClassMapping<Item>
    {
        public ItemMap()
        {
            Lazy(false);
            Id(x => x.ID, map => map.Generator(Generators.HighLow,
                          gmap => gmap.Params(new {max_low = 100})));
            Property(x => x.Name,
                          map => { map.Length(150); map.NotNullable(true); });
            Property(x => x.Description,
                          map => { map.Length(1000); map.NotNullable(true); });
            ManyToOne(x => x.Category, map =>
                                           {
                                               map.Column("CategoryID");
                                               map.NotNullable(true);
                                               map.Lazy(LazyRelation.NoProxy);
                                           });
            Bag(x => x.Pictures,
               collectionMapping =>
               {
                   collectionMapping.Table("ItemPictures");
                   collectionMapping.Access(Accessor.NoSetter);
                   collectionMapping.Cascade(Cascade.All);
                   collectionMapping.Key(k => k.Column("ItemID"));
                   collectionMapping.Lazy(CollectionLazy.NoLazy);
               },
               mapping => mapping.Component(PictureInfoMap.Mapping()));
        }
    }

This mapping code mark the class as non-lazy loaded, define the Id field with a generation strategy, defines name and description simple properties.

Then comes the association of many to one to category entity through Category property, and define the mapping column name in the database, and define the lazy loading strategy of the collection.

The association to a list of PictureInfo value objects is done through Bag given the property name Pictures, and a collection mapping which describes the database table to be mapped to, the cascading strategy, the key name, and lazy loading strategy, and the accessor strategy to state that this collection will have no setter.

As the PictureInfo is a value object and not an entity, there is no separate mapper class for it and it does not have identity, so the mapping would be in place through Component, but for modularity the behavior of component mapping for PictureInfo is encapsulated in PictureInfoMap.Mapping() method which is defined as the following:

    public class PictureInfoMap
    {
        private const int MaxImageLength = 3145728; // = 3 MB

        public static Action<IComponentElementMapper<PictureInfo>> Mapping()
        {
            return c =>
            {
                c.Property(p => p.Title, map => map.Length(150));
                c.Property(p => p.FileName, map => map.NotNullable(true));
                c.Property(p => p.IsMain, map => map.NotNullable(true));
                c.Property(p => p.Picture, map =>
                               {
                                    map.NotNullable(true);
                                    map.Length(MaxImageLength);
                               });
            };
        }
    }
  • ItemCategoryMap:
        public ItemCategoryMap()
        {
            Lazy(false);
            Id(x => x.ID, map => map.Generator(Generators.HighLow, gmap =>
                                 gmap.Params(new {max_low = 100})));
            Property(x => x.Name, map => { map.Length(150); map.NotNullable(true); });
            Bag(x => x.AvailableConditions,
                collectionMapping =>
                    {
                        collectionMapping.Access(Accessor.NoSetter);
                        collectionMapping.Cascade(Cascade.All);
                        collectionMapping.Key(k => k.Column("ItemConditionID"));
                        collectionMapping.Lazy(CollectionLazy.NoLazy);
                    },
                mapping => mapping.Component(ItemConditionMap.MappingElements()));
        }
    }

This mapping code mark the class as non-lazy loaded, define the Id field with a generation strategy, defines name property.

And again it defines a bag of component for ItemCondition value object.

  • AdMap:
    public class AdMap : ClassMapping<Ad>
    {
        public AdMap()
        {
            Lazy(false);
            Id(x => x.ID, map => map.Generator(Generators.HighLow, gmap =>
                                 gmap.Params(new {max_low = 100})));
            ManyToOne(x => x.Customer, map =>
                                           {
                                               map.Column("CustomerID");
                                               map.NotNullable(true);
                                               map.Lazy(LazyRelation.NoProxy);
                                           });
            ManyToOne(x => x.Item, map =>
            {
                map.Column("ItemID");
                map.NotNullable(true);
            });
            Property(x => x.Description, map => { map.Length(1000);
                                                  map.NotNullable(true); });
            Property(x => x.Price, map => map.NotNullable(true));
            Property(x => x.CreationDate, map => map.NotNullable(true));
            Component(x => x.Condition, ItemConditionMap.Mapping());
            Bag(x => x.Pictures,
                collectionMapping =>
                    {
                        collectionMapping.Table("AdPictures");
                        collectionMapping.Access(Accessor.NoSetter);
                        collectionMapping.Cascade(Cascade.All);
                        collectionMapping.Key(k => k.Column("AdID"));
                        collectionMapping.Lazy(CollectionLazy.NoLazy);
                    },
                mapping => mapping.Component(PictureInfoMap.Mapping()));
        }
    }

Two many to one associations to customer and item, one value object association to Condition as a component, and like Item a bag of PictureInfo value object.

Entities and Value Objects

One of the building blocks of a Domain Driven Design application are entities and value objects.

Entity is an object with identity, it is defined by its identity and continuity not its attributes, for example a person is an entity with identity (maybe it is social security number, maybe a user id, maybe Guid) but this person remains the same even after changing his address or even his name. two instances of person objects with the same identity are the same even if they are not the same object in memory, even if they have different attributes (Properties and Fields) thus it is a mutable type, you can change its attributes and it remains the same entitiy.

Value Object on the other hand is an object that contains attributes with no conceptual identity, two value objects with the same attributes are the same. thus it is immutable type, when you change any attribute of value object it becomes a different value object. an example of value object is address (unless your application domain states that address is a key information with identity like shipping applications), the address is a value object attached to the person, you can not identify address on its own, you just can fetch a person entity and get the address.

When developing a DDD application in .net usually I create a Layer Super Type for entities and value objects as follows:

EntityBase: Each entity should have Identity, this identity could be an int (auto number), a Guid, a string, custom identity object, or any type. this identity should be the base of object hash code, equality, and comparing operators. the following base class handles these aspects:

    public abstract class EntityBase<TEntity, TID> :
        IEquatable<EntityBase<TEntity, TID>>
        where TEntity : EntityBase<TEntity, TID>
    {
        #region Identity

        public virtual TID ID { get; protected set; }

        #endregion

        #region Overrides

        /// <summary>
        /// Indicates whether the current object
        /// is equal to another object of the same type.
        /// </summary>
        /// <returns>
        /// true if the current object is equal
        /// to the <paramref name="other"/> parameter;
        /// otherwise, false.
        /// </returns>
        /// <param name="other">An object to compare with this object.</param>
        public bool Equals(EntityBase<TEntity, TID> other)
        {
            if (other == null)
                return false;

            // Handle the case of comparing two NEW objects
            var otherIsTransient = Equals(other.ID, default(TID));
            var currentIsTransient = Equals(ID, default(TID));

            if (otherIsTransient && currentIsTransient)
                return ReferenceEquals(other, this);

            return other.ID.Equals(ID);
        }

        /// <summary>
        /// Equality
        /// </summary>
        public override bool Equals(object obj)
        {
            var other = obj as TEntity;

            return Equals(other);
        }

        /// <summary>
        /// Get hash code
        /// </summary>
        public override int GetHashCode()
        {
            var thisIsTransient = Equals(ID, default(TID));

            // When this instance is transient, we use the base GetHashCode()
            return thisIsTransient ? base.GetHashCode() : ID.GetHashCode();
        }

        /// <summary>
        /// Equal operator
        /// </summary>
        public static bool operator ==
            (EntityBase<TEntity, TID> x, EntityBase<TEntity, TID> y)
        {
            return Equals(x, y);
        }

        /// <summary>
        /// Not equal operator
        /// </summary>
        public static bool operator !=
            (EntityBase<TEntity, TID> x, EntityBase<TEntity, TID> y)
        {
            return !(x == y);
        }

        #endregion
    }

The entity base has two generic parameters, one for the type of entity TEntity, and the other for identity type TID, it implements IEquatable .net interface.

ID field is defined in line 7 using the TID type.

Implementation of strongly typed IEquatable Equals method and Object override Equals methods are provided to handle equality of two entities given and check their transient state. transient means that the entity has been created without setting the ID yet, thus the ID have a default value based on type (if reference type will be null, if primitive type will hold the default value), of course there should not be an entity defined with an id of null or default value. if both entities are transient then we have to check if they point to the same memory address thus they are the same object in terms of .net, otherwise we shall compare the identities.

The equals and not equals operators are also implemented and the GetHashCode also should return the identity’s hash code.

ValueObjectBase: Value object have no Identity, object hash code should represent the hash code of all it’s attributes, equality, and comparing operators should compare all and each field in the object:

    public class ValueObjectBase<TValueObject> :
        IEquatable<TValueObject>
        where TValueObject : ValueObjectBase<TValueObject>
    {
        #region Overrides

        /// <summary>
        /// Indicates whether the current object
        /// is equal to another object of the same type.
        /// </summary>
        /// <returns>
        /// true if the current object is equal
        /// to the <paramref name="other"/> parameter; otherwise, false.
        /// </returns>
        /// <param name="other">An object to compare with this object.</param>
        public bool Equals(TValueObject other)
        {
            if (other == null)
                return false;

            // Compare all public properties
            var publicProperties = GetType().GetProperties();

            if (publicProperties != null && publicProperties.Any())
                return publicProperties
                    .All(item => item.GetValue(this, null)
                    .Equals(item.GetValue(other, null)));

            return true;
        }

        /// <summary>
        /// Equality
        /// </summary>
        public override bool Equals(object obj)
        {
            // If both are null, or both are same instance, return true
            if (ReferenceEquals(obj, this))
                return true;

            if (obj == null)
                return false;

            var item = obj as ValueObjectBase<TValueObject>;

            if (item == null)
                return false;

            return Equals((TValueObject) item);
        }

        /// <summary>
        /// Get hash code
        /// </summary>
        public override int GetHashCode()
        {
            var hashCode = 31;
            var changeMultiplier = false;
            const int index = 1;

            // Compare all public properties
            var publicProperties = GetType().GetProperties();

            if (publicProperties != null && publicProperties.Any())
            {
                foreach (var value in publicProperties
                    .Select(item => item.GetValue(this, null)))
                {
                    if (value != null)
                    {
                        hashCode = hashCode * ((changeMultiplier) ? 59 : 114)
                            + value.GetHashCode();
                        changeMultiplier = !changeMultiplier;
                    }
                    else
                        hashCode = hashCode ^ (index * 13); // Support order
                }
            }

            return hashCode;
        }

        /// <summary>
        /// Equal operator
        /// </summary>
        public static bool operator ==
            (ValueObjectBase<TValueObject> x, ValueObjectBase<TValueObject> y)
        {
            return Equals(x, y);
        }

        /// <summary>
        /// Not equal operator
        /// </summary>
        public static bool operator !=
            (ValueObjectBase<TValueObject> x, ValueObjectBase<TValueObject> y)
        {
            return !(x == y);
        }

        #endregion
    }

This implementation is taken from Cesar de la Torre which uses reflection to compare all the fields of the value object.