Primary keys may take several forms: guid, integer, long, etc. It often makes sense to represent the key field as a POCO rather than its native type.
Why would I do this?
First, it hides the implementation. I don't have to worry about whether the key is an integer or a long, instead, I interact with my complex type.
It allows me to do some more interesting things with a key, too. For example, let's say I did choose to use identity fields (integers) so one implementation of my key is a "CoreKey" that contains an "ID" of type Integer.
It is common to see people use 0 or -1 as a "null" or "uninitialized" value for this type of key. With my class, I can do a little more and define it like this:
[Serializable]
public class CoreKey : IComparable<CoreKey>, IEquatable<CoreKey>, ICloneable
{
private const int NOT_INITIALIZED = -1;
public int ID { get; set; }
public static CoreKey Empty
{
get
{
return new CoreKey(NOT_INITIALIZED);
}
}
public CoreKey()
{
ID = NOT_INITIALIZED;
}
public CoreKey(int id)
{
ID = id;
_Initialize();
}
private void _Initialize()
{
if (ID <= 0)
{
ID = NOT_INITIALIZED;
}
}
public static bool IsNullOrEmpty(CoreKey coreKey)
{
return coreKey == null || coreKey.ID.Equals(NOT_INITIALIZED);
}
public static bool TryParse(string value, out CoreKey coreKey)
{
bool retVal = false;
int id;
if (int.TryParse(value, out id))
{
coreKey = new CoreKey(id);
retVal = true;
}
else
{
coreKey = null;
}
return retVal;
}
Notice that when I create a key (CoreKey key = new CoreKey()), it is immediately initialized to CoreKey.Empty, a special value I can check for. Instead of "if id < 1", I can use "CoreKey.IsNullOrEmpty" and I can even TryParse this.
This is all and well until you try to wire the class into NHibernate. The classic example for an NHibernate mapping file goes something like this:
="1.0" ="utf-8"
<nhibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="MyApp.Widget,MyApp" table="widgets">
<id name="Id" column="WidgetId">
<generator class="native"/>
</id>
<property name="WidgetName" column="name" type="String" length="40"/>
</class>
</nhibernate-mapping>
That's all good and well, but our widget uses a CoreKey, right? So what now? Try to reference the type, and you start to have problems:
<id name="Id" column="WidgetId" type="Framework.CoreKey,MyApp"/>
Of course, this will blow up. Why? Because the type coming from the database is an integer, and our CoreKey is NOT an integer. So what do we do?
This seems like it should be a simple problem to solve, but I searched far and wide to find a solution. I was trying components and composite keys and everything in between. I finally found an example that mentioned using the special interface IUserType supplied by NHibernate to, well, create our own types.
Unfortunately, the example included referencing NHibernate, my "persistence engine" or data layer, and then applying the interface to my domain object ("business entity"). Can you imagine dirtying your entity layer with ugly references to the implementation of your data store? Shouldn't, couldn't, and wouldn't happen.
Fortunately, the solution was rather simple and straightforward. Thanks to C# and inheritance, my domain objects only have to know about a CoreKey. However, my data layer can interact with something smarter, something that implements the IUserType interface AND talks the language of CoreKey.
Introducing CoreKeyProxy, an object defined in the data layer of the application. Here is the meat ... I've edited out comments and some of the other methods, and included the key items that map the database values to the custom type:
public class CoreKeyProxy : CoreKey, IUserType
{
public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
{
object r = rs[names[0]];
if (r == DBNull.Value)
return null;
return new CoreKey((int)r);
}
public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
{
IDataParameter parameter = (IDataParameter)cmd.Parameters[index];
parameter.Value = value == null ? null : (object)((CoreKey)value).ID;
}
public Type ReturnedType
{
get { return typeof(CoreKey); }
}
public global::NHibernate.SqlTypes.SqlType[] SqlTypes
{
get { return new[] { new SqlType(DbType.Int32) }; }
}
}
Now I simply define my id as type="CoreKeyProxy" and voila! I'm able to integrate it seamless with my key class.

Jeremy Likness is a Microsoft Silverlight MVP who works as Project Manager and Senior Consultant for Wintellect with 15 years of experience developing enterprise applications. He has worked with software in multiple verticals ranging from insurance, health and wellness, supply chain management, and mobility. His primary focus for the past decade has been building highly scalable web-based solutions using the Microsoft technology stack with a focus on Silverlight since version 2.0.
Prior to Wintellect, Jeremy was Director of Information Technology and served as development manager and architect for AirWatch, LLC, where he helped the company grow and solidify its position as one of the leading wireless technology solution providers in the United States by managing the development of their product portfolio that includes public HotSpot solutions and a management console for enterprise grade wireless networks, mobile devices, and their consumers. A fluent Spanish speaker, Jeremy served as Director of Information Technology for Hispanicare, where he architected a multi-lingual content management system for the company's Hispanic-focused online diet program. Jeremy accepted his role there after serving as Development Manager for Manhattan Associates, a software company that provides supply chain management solutions.