Зачастую при работе с БД(да и не только), особенно при использовании какого-нибудь ОРМ, возникает задача упрощения тех или иных процедур, которые приходится вызывать очень часто(к примеру открытие транзакции и её коммит, запросы с NOLOCK или банальный препроцессинг данных). Конечно все можно сделать по-старинке:
Но «Шурик, это же не наш метод!»®. Потому мы пойдем дальше и воспользуемся более гуманными средствами а именно AOP и IOC (что это такое и с чем его едят вы можете почитать в интернете, потому не вижу смысла описывать это здесь)
До некоторых пор я использовал Unity, но что-то разонравилось мне оно и я решил его(её) сменить. Альтернативных вариантов много (Spring.Net AOP, Castle, PostSharp, Aspect#, LinFu и т.д.). Мой выбор пал на LinFu уж больно часто о нем упоминается на безграничных просторах интернета. В данном экскурсе я рассмотрю простой пример реализации транзакций при использовании NHibernate, ну и если будут многочисленные просьбы трудящихся продолжу в следующих.
Итак приступим.
Для начала скачиваем необходимые библиотеки
Открываем студию, создаем проект и добавляем необходимые ссылки на наши билиотеки(NHibernate, LinFu ну и что вы там еще собираетесь использовать), создаем объекты БД и маппинги к ним и DAO. Это я думаю вы и так умеете. Для удобства я создал базовый класс для DAO:
public class NHibernateDao
{
ISession _session;
/// <summary>
/// Gets NHibernate Session
/// </summary>
public ISession Session
{
get
{
return _session??this.DoGetSession();
}
}
//some code stripped
}
И соответственно наследуем все DAO от него. И вот все готово можно приступать. дабы код смотрелся симпатичнее и гуманнее мы воспользуемся атрибутами. Сперва создаем базовый атрибут для перехвата
public abstract class InterceptionAttribute: Attribute
{
public abstract IInvokeWrapper GetInvokeWrapper();
//или так кому как нравится.
public abstract IInterceptor GetInterceptor();
}
IInvokeWrapper и IInterceptor — это интерфейсы линфу для перехвата вызываемых методов.
NB. Выбрать надо один из методов. не надо использовать оба — дальше поймете почему.
теперь собственно атрибут перехватчик:
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class TransactionAttribute:InterceptionAttribute
{
public override IInvokeWrapper GetInvokeWrapper()
{
return new TransactionInvokeWrapper();
}
//или так кому как нравится.
public override IInterceptor GetInterceptor()
{
return new TransactionInterceptor();
}
}
ну и сами перехватчики:
public class TransactionInterceptor : IInterceptor
{
public object Intercept(IInvocationInfo info)
{
if (!(info.Target is NHibernateDao))
{
throw new InvalidOperationException("Transaction Attribute must be implemeted inside NHibernateDao class or its children");
}
(info.Target as NHibernateDao).Session.Transaction.Begin();
var returnValue = info.TargetMethod.Invoke(info.Target, info.Arguments);
try
{
(info.Target as NHibernateDao).Session.Transaction.Commit();
}
catch (DataException e)
{
(info.Target as NHibernateDao).Session.Transaction.Rollback();
throw e;
}
return returnValue;
}
}
Или вот так если вы выбрали второй метод.
public class TransactionInvokeWrapper : IInvokeWrapper
{
bool intercepted = true;
public object DoInvoke(IInvocationInfo info)
{
return info.TargetMethod.Invoke(info.Target, info.Arguments);
}
public void BeforeInvoke(IInvocationInfo info)
{
(info.Target as NHibernateDao).Session.Transaction.Begin();
}
public void AfterInvoke(IInvocationInfo info, object returnValue)
{
try
{
(info.Target as NHibernateDao).Session.Transaction.Commit();
}
catch (DataException e)
{
(info.Target as NHibernateDao).Session.Transaction.Rollback();
throw e;
}
}
}
Эти два класса были упрощены: не надо привязываться к конкретному классу, лучше сделать получении Сессии через рефлексию. Я думаю тут коментарии излишни ибо названия методов говорят за себя.
Ну вот теперь у нас готовы атрибуты и их можно расставить над нужными методами. На этом я наверное закончу первую часть ибо дальше мы уже перейдем непосредственно вглубь этого безобразия, а это заслуживает отдельной статьи. А вы пока можете выполнить вышеописанные действия.
Комментарии (1)
RSS свернуть / развернутьNetCoder
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.