My Own Version of nHybernate






1.88/5 (9 votes)
An article on reflection, attributes and database manipulation with a touch of 3tier architectural design pattern

Introduction
This article demonstrates the general programming methodology for enterprise applications while talking about attributes and reflection. I will create a set of attribute classes, implement them and then I will create a class that will use the attributes set in another class and manipulate a database table.
Background
For me, the most interesting part of programming is how things work. I have always wondered why NHybernate is so mapping-dependent until I was told (not confirmed) that it also uses attributes. I was also made aware of the fact that LINQ uses attributes. That was rather exciting so I went ahead to write my own implementation and found it very useable on some of my personal projects. Now, I want to share it with you.
Using the Code
The Basis for the Attribute class is something like this:
/// <summary>
/// Attribute definition for a table (used only at class level)
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class TableAttribute : System.Attribute
{
private string _TableName;
/// <summary>
/// Constructor
/// </summary>
/// <param name="tableName">The table name</param>
public TableAttribute(string tableName)
: base()
{
_TableName = tableName;
}
/// <summary>
/// Specify the name of the table for use in PPDataCore
/// </summary>
public string TableName
{
get
{
return _TableName;
}
set
{
_TableName = value;
}
}
}
It defines an attribute class that will be used by a DTO class (e.g User, which defines the table it maps to).
I also have the ColumnAttribute
class:
/// <summary>
/// Attribute definition for a column (used only at property level)
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class ColumnAttribute : System.Attribute
{
private string _ColumnName;
private string _ColumnType;
private KeyType _Key;
/// <summary>
/// Constructor
/// </summary>
/// <param name="columnName">Column name</param>
/// <param name="columnType">Column type</param>
/// <param name="key">key type (if key column)</param>
public ColumnAttribute(string columnName, string columnType, KeyType key)
: base()
{
_ColumnName = columnName;
_ColumnType = columnType;
_Key = key;
}
/// <summary>
/// Column name
/// </summary>
public string ColumnName
{
get
{
return _ColumnName;
}
set
{
_ColumnName = value;
}
}
/// <summary>
/// Column type
/// </summary>
public string ColumnType
{
get
{
return _ColumnType;
}
set
{
_ColumnType = value;
}
}
/// <summary>
/// Key type (if key column)
/// </summary>
public KeyType Key
{
get
{
return _Key;
}
set
{
_Key = value;
}
}
}
This defines some attributes that will be used to map the properties of the User
class to the columns of the User table.
We can now go ahead and implement the Attributes class in our User
class.
[Table("Users")]
public class User
{
private int _ID;
private string _UserName;
private string _FirstName;
private string _LastName;
private DateTime _BirthDate;
[Column("ID", "System.Int32", KeyType.AutoGenerate)]
public int ID
{
get
{
return _ID;
}
set
{
_ID = value;
}
}
[Column("UserName", "System.String", KeyType.None)]
public string UserName
{
get
{
return _UserName;
}
set
{
_UserName = value;
}
}
All these have to be dealth with, of course, and that is done right here:
private List<ColumnDef> list;
string TableName = "";
private string keyColum;
private string _QueryString;
private object _CurrentObject;
private Type _ObjectType;
/// <summary>
/// Bulk of the work is done here
/// </summary>
/// <param name="obj">The object instance to manipulate (if any), specify
/// null if none</param>
/// <param name="qType">The type of the object to be manipulated</param>
private void GenerateTableManipStrings(object obj, QueryType qType)
{
_CurrentObject = obj;
if (_CurrentObject != null && _CurrentObject.GetType() != _ObjectType)
{
return;
}
ColumnDef col = new ColumnDef();
list = new List<ColumnDef>();
_QueryString = "";
keyColum = "";
obj = _ObjectType.GetCustomAttributes(typeof(TableAttribute), false);
Array attsT = (Array)obj;
if (attsT.Length == 0)
{
TableName = _ObjectType.Name;
}
else
{
TableName = ((TableAttribute)attsT.GetValue(0)).TableName;
}
PropertyInfo[] props = _ObjectType.GetProperties();
foreach (PropertyInfo prop in props)
{
try
{
if (_CurrentObject != null)
{
col.Value = prop.GetValue(_CurrentObject, null);
}
object p = prop.GetCustomAttributes(typeof(ColumnAttribute), false);
Array attsC = (Array)p;
if (attsC.Length == 0)
{
col.Name = prop.Name;
col.Parameter = "@" + prop.Name;
col.Type = prop.PropertyType.ToString();
}
else
{
ColumnAttribute cAtt = (ColumnAttribute)attsC.GetValue(0);
col.Name = cAtt.ColumnName;
col.Parameter = "@" + cAtt.ColumnName;
col.Type = cAtt.ColumnType;
col.Key = cAtt.Key;
if ((cAtt.Key == KeyType.Primary || cAtt.Key ==
KeyType.AutoGenerate) && keyColum == "")
{
keyColum = cAtt.ColumnName;
}
else if ((cAtt.Key == KeyType.Primary || cAtt.Key ==
KeyType.AutoGenerate) && keyColum != "")
{
throw new Exception("Contains multiple key columns");
}
}
list.Add(col);
}
catch (Exception exp)
{
throw exp;
}
}
}
Points of Interest
Well that's about it. You can see that with Reflection, you can achieve just about anything in the world (literally). You can download the full source code project at the top.
History
This is the First Post - 14th April, 2008