This is part of a continuing series of posts on Fluent NHiberate.
- Using Fluent NHibernate in Rhinestone – Part I
In this part I’ll show how you can map custom user types using Fluent NHibernate.
In a previous post I had discussed the need to use custom user types in Rhinestone and had ended with a promise to have a follow up post on the details on implementing the custom user type and provide mappings for using that custom user type in NHibernate.
Revisiting the previous post, the need arises for a customer user type because the Project domain entity contains properties such as Owner that return a IUser instance and also the Members association that contains a list of IUser types representing members of the project.
The first obvious issue is that Rhinestone doesn’t have any knowledge of an identity and authentication system. It merely stores the username associated with the IUser instance. So when retrieving a Project instance from the data store, we need a way to somehow hydrate the stored username string to a IUser instance.
IUser instances can be resolved via the IUsersService domain service. So first thing to do is to start with an implementation of ICompositeUserType that will provide logic to convert the underlying username string to a IUser instance, by using the IUsersService domain service, and vice versa.
Why ICompositeUserType as opposed to IUserType?
NHibernate provides two ways of defining custom types, one is by providing an implementation that inherits from IUserType and the other is ICompositeUserType. The advantage of ICompositeUserType over an IUserType interface is that types that implement ICompositeUserType allow them to be used in advanced query scenarios where you can query based on the individual properties of the custom type that the ICompositeUserType handles.
The additional benefit is that you can map multiple columns that a single user type using the ICompositeUserType. For example a Money user type could contain two columns in the table, one Amount and one Currency, the ICompositeUserType interface allows you to map both columns to a Money type.
Implementing a abstract base class for implementing ICompositeUserType
[Disclaimer: I got the idea for a generic ICompositeUserType implementation for this blog post: http://geekswithblogs.net/opiesblog/archive/2006/08/13/87880.aspx.]
Since there are many times I have had to implement either a IUserType or ICompositeUserType in my projects I’ve decided to add a base class to NCommon.NHibernate project called CompositeUserTypeBase to ease some of the pain in implementing custom type mapping for NHibernate. I’ll list some of the implementation details of this base class here and how you can use it to implement your own mappings for your custom types.
One functionality I wanted to implement in the CompositeUserTypeBase class is to use expressions to specify the mapped properties rather than strings. Doing so while allow me to avail compile time checking and also refactoring support where if I rename my properties, the mappings specified in my CompositeUserTypeBase implementations will also change. Hence reducing the surface areas for errors.
So let me start by explaining how you can use CompositeUserTypeBase to provide mapping for your custom type and later on I’ll get into the guts of the CompositeUserTypeBase and how it is implemented. Lets say you have a money data type, very common for commerce based applications, and you want to map that data type to a set of columns in the database. A money instance is made up of the amount and currency. These values are stored as separate columns in the database.
Here’s the Money class:
public class Money
{
#region properties
public decimal Amount { get; set; }
public string Currency { get; set; }
#endregion
#region methods
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
return obj.GetType() == typeof(Money) && this.Equals((Money)obj);
}
public virtual bool Equals(Money obj)
{
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
return obj.Amount == this.Amount && Equals(obj.Currency, this.Currency);
}
public override int GetHashCode()
{
unchecked
{
return (this.Amount.GetHashCode() * 397) ^ (this.Currency != null ? this.Currency.GetHashCode() : 0);
}
}
#endregion
}
Lets start implementing a user type mapping for Money. Lets create a new class called MoneyUserType that will inherit from CompositeUserTypeBase class:
public class MoneyUserType : CompositeUserTypeBase<Money>
{
#region Overrides of CompositeUserTypeBase<Money>
/// <summary>
/// Inherits must build up the underlying type and return it.
/// </summary>
/// <param name="propertyValues">An array of objects that contain the values retrieved from the database.</param>
/// <returns></returns>
protected override Money CreateInstance(object[] propertyValues)
{
throw new NotImplementedException();
}
/// <summary>
/// Performs a deep copy of a source entity.
/// </summary>
/// <param name="source">The source entity whose deep copy should be returned.</param>
/// <returns>T</returns>
/// <remarks>
/// Inheritors must return a cloned or deep copied instance of the provided entity. If
/// </remarks>
protected override Money PerformDeepCopy(Money source)
{
throw new NotImplementedException();
}
/// <summary>
/// Are objects of this type mutable?
/// </summary>
public override bool IsMutable
{
get { throw new NotImplementedException(); }
}
#endregion
}
The type specified as the generic parameter of the ComposteUserTypeBase is the type that will be returned. Right off the bat you’ll notice three members that must be overriden by inheritors of CompositeUserTypeBase class. I’ll get to those in a bit, but first lets see how you can specify what properties are mapped. To map the properties of the data type that will be queried upon, you can use the MapProperty method in the default constructor.
#region .ctor
/// <summary>
/// Default Constructor.
/// </summary>
public MoneyUserType()
{
MapProperty(prop => prop.Currency);
MapProperty(prop => prop.Amount);
}
#endregion
In the above code snippet I am using lambdas to specify that both the Currency and Amount property should be mapped.
The first method that the CompositeUserTypeBase class you must override is CreateInstance. This method is given an array of objects containing the values read from the underlying data store and it’s the child class’s responsibility to construct an instance of the underlying data type and return that instance. The reason CompositeUserTypeBase class doesn’t attempt at constructing an instance on it’s own is because there are many scenarios where custom actions need to take place before returning an instance (Rhinestone has this requirement). So instead the CompositeUserTypeBase class offloads the responsibility of constructing instances to the child class.
/// <summary>
/// Inherits must build up the underlying type and return it.
/// </summary>
/// <param name="propertyValues">An array of objects that contain the values retrieved from the database.</param>
/// <returns></returns>
protected override Money CreateInstance(object[] propertyValues)
{
return new Money()
{
Currency = propertyValues[0].ToString(),
Amount = (decimal)propertyValues[1]
};
}
The next method to override is PerformDeepCopy. Basically this method is called whenever NHibernate calls the DeepCopy method on IComposuteUserType. This method is called whenever NHibernate needs a clone of the current data type (mostly for change tracking I believe, but I could be wrong here).
/// <summary>
/// Performs a deep copy of a source entity.
/// </summary>
/// <param name="source">The source entity whose deep copy should be returned.</param>
/// <returns>T</returns>
/// <remarks>
/// Inheritors must return a cloned or deep copied instance of the provided entity. If
/// </remarks>
protected override Money PerformDeepCopy(Money source)
{
return source == null ? null : new Money
{
Currency = source.Currency,
Amount = source.Amount
};
}
And last but not least is the IsMutable property.
/// <summary>
/// Are objects of this type mutable?
/// </summary>
public override bool IsMutable
{
get { return true; }
}
That’s it.
So what does CompositeUserTypeBase base do?
The CompositeUserTypeBase class implements the ICompositeUserType interface provided by NHibernate and implements some of the repeated logic required for implementing the interface (keeping DRY principle in check). First lets look at the MapProperty method that was used by MoneyUserType in the constructor to provide property mappings.
/// <summary>
/// Maps a property for the composite user type.
/// </summary>
/// <param name="property">A expression representing the property to map.</param>
protected virtual void MapProperty(Expression<Func<T, object>> property)
{
Guard.Against<ArgumentNullException>(property == null, "Expected a non-null Expression that represents the property to map.");
var visitor = new MemberAccessPropertyInfoVisitor();
visitor.Visit(property);
_properties.Add(visitor.Property);
}
MapProperty basically accepts a Expression<Func<T, bool>> instance that represents the property of the underlying type that should be mapped. What this method does is uses a specialized ExpressionVisitor, MemberAccessPropertyInfoVisitor in NCommon, and stores the underlying PropertyInfo in an internal list. These properties come into play in other methods and properties.
All other members of the base class are implementation of ICompositeUserType interface.
ICompositeUserType.ReturnedClass
The ICompositeUserType.ReturnedType property should return the type that your ICompositeUserType will map the underlying column(s) value(s) to. CompositeUserTypeBase basically returns the type of the specified generic parameter.
/// <summary>
/// The class returned by NullSafeGet().
/// </summary>
public Type ReturnedClass
{
get { return typeof(T); }
}
ICompositeUserType.PropertyNames
This property should return an array of strings containing all the properties that will participate in a query. CompositeUserTypeBase builds this array of strings by enumerating over the list of PropertyInfo instances that were stored in an internal list when the child class called MapProperty.
/// <summary>
/// Get the "property names" that may be used in a query.
/// </summary>
public string[] PropertyNames
{
get
{
var names = new string[_properties.Count];
for (var i = 0; i < _properties.Count; i++)
names[i] = _properties[i].Name;
return names;
}
}
ICompositeUserType.PropertyTypes
This property should return the data types of the properties returned by the PropertyNames property. And just like in the PropertyNames implementation, CompositeUserTypeBase class uses the internal PropertyInfo list to build the array. It uses NHibernateUtil.GuessType to guess the underlying type. [This may not be ideal in all scenarios and that’s why PropertyTypes is marked virtual so that you can override the default behavior if you need to]
/// <summary>
/// Get the corresponding "property types"
/// </summary>
public virtual IType[] PropertyTypes
{
get
{
var types = new IType[_properties.Count];
for (var i = 0; i < _properties.Count; i++)
types[i] = NHibernateUtil.GuessType(_properties[i].PropertyType);
return types;
}
}
ICompositeUserType.GetPropertyValue
This method is called to retrieve the value of a mapped property. The property parameter contains the ordinal value of the property in the array of property names passed by the PropertyNames property. CompositeUserTypeBase basically retrieves the underlying PropertyInfo from the internal list and calls GetValue on it.
/// <summary>
/// Get the value of a property
/// </summary>
/// <param name="component">an instance of class mapped by this "type"</param>
/// <param name="property"></param>
/// <returns>
/// the property value
/// </returns>
public object GetPropertyValue(object component, int property)
{
var propInfo = _properties[property];
return propInfo.GetValue(component, null);
}
ICompositeUserType.SetPropertyValue
Just like GetPropertyValue, SetPropertyValue sets the value of a property for the underlying data type.
/// <summary>
/// Set the value of a property
/// </summary>
/// <param name="component">an instance of class mapped by this "type"</param>
/// <param name="property"></param>
/// <param name="value">the value to set</param>
public void SetPropertyValue(object component, int property, object value)
{
var propInfo = _properties[property];
propInfo.SetValue(component, value, null);
}
ICompositeUserType.Equals
CompositeUserTypeBase basically delegates equality comparison the underlying type since it cannot make any guarantees about equality. Unless the both objects have the same reference pointer, this method calls the underlying data type’s Equals implementation. Remember to override Equals in your data type to ensure proper equality comparison.
/// <summary>
/// Get a hashcode for the instance, consistent with persistence "equality"
/// </summary>
public int GetHashCode(object x)
{
return x.GetHashCode();
}
ICompositeUserType.NullSafeGet
Now we come to the meat of the ICompositeUserType interface. This method is called by NHibernate to construct the underlying data type based on the data retrieved from the database. The key here is the names parameter passed to NullSafeGet. The names parameter contains an array of strings that represent the column names specified in the mappings file and they are specified in the same order. This order should be remember because that same order is expected by CompositeUserTypeBase when mapping properties.
For example, if your mapping file specifies the Amount column first and then Currency, then the child class should call MapProperty (prop => prop.Amount) and then MapProperty(prop => prop.Currency) to make sure that both mappings are in the same order.
Here’s the implementation.
/// <summary>
/// Retrieve an instance of the mapped class from a IDataReader. Implementors
/// should handle possibility of null values.
/// </summary>
/// <param name="dr">IDataReader</param>
/// <param name="names">the column names</param>
/// <param name="session"></param>
/// <param name="owner">the containing entity</param>
/// <returns>
/// </returns>
public object NullSafeGet(IDataReader dr, string[] names, ISessionImplementor session, object owner)
{
if (dr == null)
return null;
var values = new object[names.Length];
for (var i = 0; i < names.Length; i++)
values[i] = NHibernateUtil.GuessType(_properties[i].PropertyType)
.NullSafeGet(dr, names[i], session, owner);
return CreateInstance(values);
}
ICompositeUserType.NullSafeSet
NullSafeSet is the opposite of NullSafeGet where NullSafeSet is called to update the underlying data store with the values in the data type. Just like NullSafeGet, the ordinal values of the property names and column mappings are important.
/// <summary>
/// Write an instance of the mapped class to a prepared statement.
/// Implementors should handle possibility of null values.
/// A multi-column type should be written to parameters starting from index.
/// </summary>
/// <param name="cmd"></param>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="session"></param>
public void NullSafeSet(IDbCommand cmd, object value, int index, ISessionImplementor session)
{
if (value == null)
return;
var propIndex = index;
for (var i = 0; i < _properties.Count; i++)
{
var property = _properties[i];
var propValue = property.GetValue(value, null);
NHibernateUtil.GuessType(property.PropertyType).NullSafeSet(cmd, propValue, propIndex, session);
propIndex++;
}
}
ICompositeUserType.Assembly, Disassemble and Replace
These three methods simply return the result from DeepCopy. They are virtual so if you need to provide any custom logic you can override them in your child class.
That’s about it for the CompositeUserTypeBase class. Full source and tests are part of NCommon so you can get the source code from codeplex.
Enough of ICompositeUserType nonsense, what about the mappings?
Okay, so I’ve taken the topic of custom user types in NHibernate as far as I can. Now that I have a base class for implementing user types, here is the child class for implementing a custom type for IUser in Rhinestone.
public class RhinestoneUserType : CompositeUserTypeBase<IUser>
{
#region .ctor
public RhinestoneUserType()
{
MapProperty(prop => prop.Username);
}
#endregion
#region Overrides of CompositeUserTypeBase<IUser>
protected override IUser CreateInstance(object[] propertyValues)
{
var usersService = ServiceLocator.Current.GetInstance<IUsersService>();
return usersService.FindUserByName((string) propertyValues[0]);
}
protected override IUser PerformDeepCopy(IUser source)
{
return source; //Users are immutable and cannot be changed.
}
public override bool IsMutable
{
get { return false; }
}
#endregion
So basically at the time of CreateInstance I am resolving a IUsersService and using the FindUserByName method to get an instance of that user.
Mapping couldn’t be simpler via Fluent NHiberante. Below are the mappings in both xml and ClassMap.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Rhinestone.Domain"
namespace="Rhinestone.Domain">
<class name="Project" table="Projects">
<id name="ProjectID" access=" nosetter.camelcase-underscore">
<generator class="identity"/>
</id>
<property name="Code"/>
<property name="Name"/>
<property name="Description"/>
<property name="Owner"
column="OwnerUsername"
type="Rhinestone.Domain.Mappings.RhinestoneUserType, Rhinestone.Domain.Mappings"/>
<set name="Members" table="ProjectMembers">
<key column="ProjectID"/>
<element column="MemberUsername"
type="Rhinestone.Domain.Mappings.RhinestoneUserType, Rhinestone.Domain.Mappings"/>
</set>
</class>
</hibernate-mapping>
/// <summary>
/// Default Constructor.
/// Defines mappings for the <see cref="Project"/> entity.
/// </summary>
public ProjectMap()
{
WithTable("Projects");
Id(prop => prop.ProjectID)
.Access.AsReadOnlyPropertyThroughCamelCaseField()
.GeneratedBy.Identity();
Map(prop => prop.Code, "ProjectCode");
Map(prop => prop.Name);
Map(prop => prop.Description);
Map(prop => prop.Owner, "OwnerUsername").CustomTypeIs(typeof (RhinestoneUserType));
HasMany<RhinestoneUserType>(prop => prop.Members)
.WithTableName("ProjectMembers")
.WithKeyColumn("ProjectID")
.AsElement("MemberUsername")
.AsSet();
}
}
Using Fluent NHibernate you can specify the custom type of a property using the CustomTypeIs method. Similarly, for mapping a list of custom elements, you can use the HasMany method and specify the custom type using the generic overload of the HasMany method. The generic overload of HasMany specifies that the mapping will return the type specified as the generic parameter, instead of the type being inferred from the property as expressed by the lambda.
In the next post I’ll continue to provide mappings for Rhinestone and also show some additional mapping techniques using Fluent NHibernate and finally go into how you can use Fluent NHibernate inbuilt testing functionality to test your mappings.