I have been using Repositories and Managers for some time now. Repositories allows you to perform actions on the entities which include the basic CRUD operations and also other retrieval functions. If I am developing an application I will have repositories for all my root types. This means if I have Person and Address entity then I will have the PersonRepository which will persist the person as well as the address.
Recently, I am inclining towards a completely different approach. This approach is based on creating a single class which is responsible for invoking on different data access classes.
So instead of typing this:
PersonRepository.Save(new Person() { FirstName = "Mohammad", LastName = "Azam" });
I can do the following:
MethodInvoker.Invoke<SQLDataAccess>(typeof(Person), "AddAndPersistAll", new Person() { FirstName = "Mohammad", LastName = "Azam" });
The MethodInvoker will allow to invoke any method which is defined on the SQLDataAccess class. SQLDataAccess class contains all the data access methods for the application. If the application consists of multiple databases then we can also use different data access classes like UserDataAccess, ArchiveDataAccess and so on.
The advantage of MethodInvoker is that we no longer have to create Repositories to perform action on our entities. I can also use Custom Attributes to cache the data. You can read my blog post about Data Caching Using Custom Attributes.
Here is the implementation of the MethodInvoker class:
public static object Invoke<T>(Type classType, string methodName, object[] parameters)
{
StringBuilder keyB = new StringBuilder();
keyB.Append(typeof(T).FullName).Append(methodName);
string key = keyB.ToString();
if (HttpContext.Current.Cache[key.ToString()] != null)
{
return HttpContext.Current.Cache[key.ToString()];
}
MethodInfo method = typeof(T).GetMethod(methodName);
object[] customAtt = method.GetCustomAttributes(false);
var cacheAtt = customAtt.Select<object, CacheAttribute>(a => a as CacheAttribute).SingleOrDefault();
if (classType != null)
{
method = method.MakeGenericMethod(new Type[] { classType });
}
object o = Activator.CreateInstance(typeof(T));
object result = null;
result = method.Invoke(o, parameters != null ? parameters : null);
if (cacheAtt != null && HttpContext.Current.Cache[key.ToString()] == null)
{
HttpContext.Current.Cache.Insert(key.ToString(), DateTime.Now, null, DateTime.Now.AddSeconds(cacheAtt.TimeInSeconds), TimeSpan.Zero);
}
return result;
}
What are your thoughts about this technique?