您的位置:首页 > 运维架构

巧用“Delegate”实现AOP事务

2014-11-30 11:28 246 查看
为了保持应用程序的完整性,事务处理,是项目开发中的必不可缺的部分,且重要性不言而喻。传统的处理方式是手动控制事务的开闭,这样,不管谁用到事务处理都得自己写一遍代码。为了方便,达到AOP效果不失为一个好办法。我们用Delegate来实现一下这个效果。

一、为了展示效果,我们先来看一个小demo:

class TestClass
{
    public void Test()
    {
        Console.WriteLine("Test");
    }
    public void DelegateTest(DelegateMethod dm)
    {
        Console.WriteLine("DelegateMethod Start");
        dm.Invoke();
        Console.WriteLine("DelegateMethod End");
    }
}
class Program
{
    static void Main(string[] args)
    {
        TestClass tc = new TestClass();
        tc.Test();
        Console.WriteLine("-------------------------------");
        tc.DelegateTest(new DelegateMethod(mc.Test));
        Console.Read();
    }
}


输出结果:



我觉得这就是AOP的方式,只是和传统的不太一样,如果把调用方和被调用方看成客户端和服务器的话,那么传统的AOP是施加在服务器端的,并在服务器端控制的,而现在我把这个权利交出来,交给客户端来控制,也就是由调用者来决定是不是要使用事务,也就是调用者自己决定用事务或非事务的方式来执行方法。

二、接下来看看具体的代码

1. 先看看SqlDAL.cs的代码:

public class SqlDAL
{
    #region
    //事务
    private SqlTransaction _SqlTrans;
    //数据库连接类
    private SqlConnectionStringBuilder _ConnectionString = null;
    #endregion

    #region delegate
    /// <summary>
    /// 用于执行带Dictionary参数无返回值的函数
    /// </summary>
    /// <param name="dict"></param>
    public delegate void VOID_DICTIONARY_METHOD(Dictionary<string, object> dict);
    #endregion

    #region Method
    #region ExecuteNonQuery
    public int ExecuteNonQuery(string cmdText)
    {
        if (SqlTrans == null)
            return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, CommandType.Text, cmdText);
        else
            return SqlHelper.ExecuteNonQuery(SqlTrans, CommandType.Text, cmdText);
    }

    public int ExecuteNonQuery(string cmdText, CommandType type)
    {
                    if (SqlTrans == null)
            return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText);
                                    else
                                        return SqlHelper.ExecuteNonQuery(SqlTrans, type, cmdText);
                }
                
    public int ExecuteNonQuery(string cmdText, CommandType type, params SqlParameter[] cmdParameters)
    {
        if (SqlTrans == null)
            return SqlHelper.ExecuteNonQuery(ConnectionString.ConnectionString, type, cmdText, cmdParameters);
                        else
            return SqlHelper.ExecuteNonQuery(SqlTrans, type, cmdText, cmdParameters);
    }
                
    #endregion
    /// <summary>
    /// 在事务中执行
    /// </summary>
    /// <param name="action"></param>
    /// <param name="args"></param>
    public void TransactionAction(Delegate delegateMethod, params object[] args)
    {
        SqlConnection SqlConnect = new SqlConnection(ConnectionString.ConnectionString);
        SqlConnect.Open();
        _SqlTrans = SqlConnect.BeginTransaction();
        try
        {
            //数据库操作
            delegateMethod.DynamicInvoke(args);
            //提交事务
            _SqlTrans.Commit();
        }
        catch (SqlException)
        {
            _SqlTrans.Rollback();
            //日志
        }
        finally
        {
            if (SqlTrans != null)
            {
                _SqlTrans.Dispose();
                _SqlTrans = null;
            }
            if (SqlConnect != null)
                SqlConnect.Close();
        }
    }
    #endregion
        
    #region Properties
    /// <summary>
    /// 仅支持有事务时操作
    /// </summary>
    public SqlTransaction SqlTrans
    {
        get { return _SqlTrans; }
        set { _SqlTrans = value; }
    }
        
    /// <summary>
    /// 字符串连接
    /// </summary>
    public virtual SqlConnectionStringBuilder ConnectionString
    {
        get
        {
            if (_ConnectionString == null || string.IsNullOrEmpty(_ConnectionString.ConnectionString))
            {
                _ConnectionString = new SqlConnectionStringBuilder(Configurations.SQLSERVER_CONNECTION_STRING);
            }
            return _ConnectionString;
        }
        set { _ConnectionString = value; }
    }        
    #endregion
}
代码说明:

把Delegate作为参数,我们可以传任何一个delegate进来,不必使用实际的如VOID_DICTIONARY_METHOD作为参数传递,这对于通用是一个很好的办法。
ransactionAction方法第二个参数是你要传递的参数,即委托的参数。MSDN:作为参数传递给当前委托所表示的方法的对象数组。- 或 - 如果当前委托所表示的方法不需要参数,则为null。

2.接下来看看 UserInfoAction.cs 和 Main 的代码:

public class UserInfoAction : SqlDAL
{
    public void Add(Dictionary<string, object> dict)
    {
        StringBuilder sql = new StringBuilder();
        sql.Append("INSERT [UserInfo](");
        ……
        ExecuteNonQuery(sql);
    }
}


static void Main(string[] args)
{
    Dictionary<string, object> dict = new Dictionary<string, object>();
    UserInfoAction uiAction = new UserInfoAction();
    dict.Add("Username", "abc");
    dict.Add("Password", "abc");
    dict.Add("Email", "over140@gmail.com");
    //普通方式执行
    //uiAction.Add(dict);
    //事务方式执行
    uiAction.TransactionAction(new UserInfoAction.VOID_DICTIONARY_METHOD(uiAction.Add), dict);
}


三、总结

1. 可以看到普通方式和事务方式执行方式不同,但是我们不用改UserInfoAction的代码!!我们在写代码尤其是维护的时候就是这样的原则,或者是增量式开发也是比较好的,尽量不去改是比较好的。现在完全满足“开闭原则”。

2. 请注意:delegate必须符合Method,否则编译时会出错的,虽然解决了统一调用的问题,但是这个delegate目前我还没想到办法解决,也就是你有一个不同参数、返回值方法就得对应一个delegate,方法名称不限制,所以一开始我们就得定义可能好几十个委托,这也是利弊所在不,不然还是很完美的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: