One of the first thing I try to implement when learning a new programming language is a Generic Data Access Layer. I hate to write repetitive code and always try to find ways of working around this. I managed to implement this in Java and PHP and had no doubt that .NET will allow me to do so. After a good bunch of reading on the net and playing around with the tutorials for a while now, I managed to implement Generic DAL by using LINQ to SQL. Here is what I did:
[ Step 1 ]:
I created a seperate Class Library to Generate all my Business Objects and handle all my Data Access Objects (DAO). In this Class Library I created a a LINQ to SQL Data Context and named it UTSDataContext.
[ Step 2 ]:
I then created a Generic class which had two Parameterized Type variables one being the class representing a Business Object and the other being the Primary Key type.
public class GenericDAO<E, K> where E : class
[ Step 3 ]:
I then added all methods that will carry out CRUD tasks. The code for the Generic DAO is as follows:
public class GenericDAO<E, K> where E : class
{
private UTSDataContext context = new UTSDataContext();
public UTSDataContext Context
{
get { return context; }
set { context = value; }
}
public virtual void save(E instance)
{
this.save();
}
public virtual void save()
{
context.SubmitChanges();
}
public virtual List<E> selectAll()
{
return context.GetTable<E>().ToList();
}
public virtual void insert(E instance)
{
context.GetTable<E>().InsertOnSubmit(instance);
context.SubmitChanges();
}
public virtual void remove(E instance)
{
context.GetTable<E>().DeleteOnSubmit(instance);
context.SubmitChanges();
}
public String getKeyProperty()
{
String primaryKeyFieldName = typeof(E).Name + "Id";
return primaryKeyFieldName;
}
public Expression<Func<E, bool>> getLambaKey(K id)
{
var parameter = Expression.Parameter(typeof(E), "e");
var propId = Expression.Property(parameter, typeof(E).GetProperty(getKeyProperty()));
return Expression.Lambda<Func<E, bool>>(Expression.Equal(propId, Expression.Constant(id)), parameter);
}
public E findById(K id)
{
return context.GetTable<E>().Single(getLambaKey(id));
}
}
}
Limitations
(1) I am not in REFLECTIONS yet in order to identify primary key property field through annotations. As such, all my primary key fields are named as follows:
Exact Table Name +"Id"
For Example, the table Department will have DepartmentId as primary key Field.
(2) There are some reasons why an Object will no longer reside in LINQ Context and as such not be monitored for Changes. The most frequent one being Deserialisation. For example, if you stored an Object in session and retrieved it later on, you will have to fetch the object again from database (by using its Primary Key Identifier perhaps) and then write the changes to it.