Search

Custom Search

Friday, June 6, 2008

Think Generic

One feature I’m starting to love with C# is the use of generic classes. We usually use some classes like List<T>, Dictionary<key, Value> which uses generic types. It expands the usage of your class through polymorphism. A simple way of how Generic works, think of adding a number or adding a string or adding fractions, what if we add objects? They all have the same verb ADD but have different implementation. A sample code is written below:

public interface GenericMath<T>
{
T Add(T Operand1, T Operand2);
T Subtract(T Operand1, T Operand2);
T Multiply(T Operand1, T Operand2);
T Divide(T Operand1, T Operand2);

}

public class IntegerMath : IGenericMath<int>
{
public int Add(int Operand1, int Operand2)
{
return Operand1 + Operand2;
}

public int Subtract(int Operand1, int Operand2)
{
return Operand1 - Operand2;
}

int Multiply(int Operand1, int Operand2)
{ … }
int Divide(int Operand1, int Operand2)
{ … }

}

Although the example below is not that useful but I hope I have explained clearly how generic works.

As I explore more on generics, I found out that it is so useful on database frameworks like DEV Force, CSLA.Net or ADO.Net Entity Framework. This frameworks uses entities as their records holders. Entities are classes defined automatically by those frameworks to make tables a strong type class. Meaning fields can be access directly as lastName = Customer.LastName unlike before that we uses string then cast it to its typle like this : lastName = (string)Row[“LastName”]. Since every classes that uses the Models returns different entities it is difficult to create a base class that will manipulate Different Entity. A Code below simplifies the Manipulation of data for Dev Force:

public class EntityManagerBase<T>: IEntityManager<T> where T : IdeaBlade.Persistence.Entity
{
private Entity defaultEntity = null;
private EntityColumn primaryKeyField = null;

private PersistenceManager data;
private T entityProperty= null;
private int numLength = 6;
private string uniqueIdPrefix;
private string uniqueNoField;
private bool explicitSave = false;

#region [Properties]
public EntityColumn PrimaryKeyField
{
get { return primaryKeyField; }
set { primaryKeyField = value; }
}
public bool ExplicitSave
{
get { return explicitSave; }
set { explicitSave = value; }
}
public string UniqueNoField
{
get { return uniqueNoField; }
set { uniqueNoField = value; }
}
public int NumLength
{
get { return numLength; }
set { numLength = value; }
}
public T EntityProperty
{
get { return entityProperty;}
set { entityProperty = value;}
}
public PersistenceManager Data
{
get { return data; }
set { data = value; }
}
public EntityManagerBase(PersistenceManager pData)
{
data= pData;
EntityProperty = (T)pData.CreateEntity(typeof(T));
}
#endregion
#region [Virtual Methods]
public virtual bool UpdateEntity(object pPrimaryKey)
{
PrimaryKey primaryKey = new PrimaryKey(typeof(T), pPrimaryKey);
T entity = data.GetEntity<T>(primaryKey);
Initialize();
AssignValues(entity);
return CheckAndSave();
}

public virtual bool UpdateEntity(params object[] pPrimaryKeys)
{
PrimaryKey primaryKey = new PrimaryKey(typeof(T), pPrimaryKeys);
T entity = data.GetEntity<T>(primaryKey);
Initialize();
AssignValues(entity);
return CheckAndSave();
}
public virtual T CreateEntity()
{
T entity = (T)data.CreateEntity(typeof(T));
uniqueNoField = "";
uniqueIdPrefix = "";
ProcessCreate(entity);
return entity;
}
public virtual T CreateEntity(string pUniqueNoField, string pUniqueIdPrefix)
{
T entity = (T)data.CreateEntity(typeof(T));
uniqueNoField = pUniqueNoField;
uniqueIdPrefix = pUniqueIdPrefix;

ProcessCreate(entity);
return entity;
}
public virtual bool DeleteEntity(object pPrimaryKey)
{
SaveResult result;
PrimaryKey pk = new PrimaryKey(typeof(T), pPrimaryKey);
Entity ent = Data.GetEntity(pk);
ent.Delete();
result = Data.SaveChanges();
Data.Clear();
return result.Ok;
}
public virtual bool DeleteEntity(params object[] pPrimaryKeys)
{
SaveResult result;
PrimaryKey pk = new PrimaryKey(typeof(T), pPrimaryKeys);
Entity ent = Data.GetEntity(pk);
ent.Delete();
result = Data.SaveChanges();
Data.Clear();
return result.Ok;
}
public virtual T GetEntityByPrimaryKey(object pPrimaryKey)
{
PrimaryKey primaryKey = new PrimaryKey(typeof(T), pPrimaryKey);
T entity = data.GetEntity<T>(primaryKey);
return entity;
}
public virtual T GetEntityByPrimaryKey(params object[] pPrimaryKeys)
{
PrimaryKey primaryKey = new PrimaryKey(typeof(T), pPrimaryKeys);
T entity = data.GetEntity<T>(primaryKey);
return entity;
}
public virtual EntityList<T> GetEntityList(EntityColumn pColumn, EntityQueryOp pQueryOp, object pValue)
{
RdbQuery rdbQ = new RdbQuery(typeof(T));
EntityList<T> aList;
rdbQ.AddClause(pColumn, pQueryOp, pValue);
aList = data.GetEntities<T>(rdbQ);
return aList;
}
public virtual EntityList<T> GetEntityList(List<Clause> Clauses)
{
RdbQuery rdbQ = new RdbQuery(typeof(T));
EntityList<T> aList;

int counter = Clauses.Count;
for(counter = 0; counter < Clauses.Count; counter ++)
{
rdbQ.AddClause(Clauses[counter].FilterColumn, Clauses[counter].QueryOperator, Clauses[counter].PassedValue);
if(counter < Clauses.Count -1 )
{
rdbQ.AddOperator(Clauses[counter].ClauseOperator);
}
}
aList = data.GetEntities<T>(rdbQ);
return aList;
}
private bool CheckAndSave()
{
if(!explicitSave)
{
if (Data.HasChanges())
{
Data.SaveChanges();
return true;
}
}
return false;
}
public bool SaveChanges()
{
if (Data.HasChanges())
{
Data.SaveChanges();
return true;
}

return false;
}
#endregion
private void AssignValues(T entity)
{
foreach (EntityColumn column in Data.GetEntityColumns(typeof(T)))
{
if (!column.IsPrimaryKeyColumn && EntityProperty[column.ColumnName] != defaultEntity[column.ColumnName])
{
entity[column.ColumnName] = EntityProperty[column.ColumnName];
}
}
}
public string GenerateNo(string prefix )
{
EntityList<T> aList = data.GetEntities<T>();
string maxNo;
if (aList.Count > 0)
{
maxNo = (Convert.ToString(Convert.ToInt32(((aList[aList.Count - 1])[primaryKeyField.ColumnName])) + 1));
}
else
{
maxNo = "1";
}

int len = maxNo.Length;
int padLength = numLength - len;
string padZero = new string('0',padLength);

return string.Format("{0}-{1}{2}", prefix, padZero, maxNo);
}
private void ProcessCreate(T entity)
{
foreach (EntityColumn column in Data.GetEntityColumns(typeof(T)))
{
if (column.IsPrimaryKeyColumn)
{
primaryKeyField = column;
break;
}
}
if(uniqueNoField != "")
{
entity[uniqueNoField] = GenerateNo(uniqueIdPrefix);
}
entity.AddToManager();
Initialize();
AssignValues(entity);
CheckAndSave();
}
private void Initialize()
{
defaultEntity = data.CreateEntity(typeof(T));
}
}
public struct Clause
{
public EntityColumn FilterColumn;
public EntityQueryOp QueryOperator;
public object PassedValue;
public EntityBooleanOp ClauseOperator;
}
}

We used it on MAN Project and it works!

Adsense Banner