• 策略模式实现支持多种类数据库的DBHelp


    概述

    需求

    有时我们的系统需要支持多种数据库,如即要支持MSSQL server又要同时支持Oracle database.而如果我们为些实现两套数据库操作的方式,就会不能很好的达到软件设计的目标:高内聚,低偶合。

    设计

    采取策略模式(Strategy),它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。

    1

    优点:

    1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
    2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
    3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

    缺点:
    1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
    2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)

    DBHelp设计目标,同时支持Sqlite、Oracle 、MySql 、MsSql,类UML图设计如下:

    DBHelpClassDesignDiagram

    有了上面的设计图如后,我们先创建Enums:

    /********************************************************************************
    ** Class Name:   Enums
    ** Author:      Spring Yang
    ** Create date: 2013-3-16
    ** Modify:      Spring Yang
    ** Modify Date: 2013-3-16
    ** Summary:     Enums  class
    *********************************************************************************/
    
    namespace BlogDBHelp
    {
        using System;
    
        [Serializable]
        public enum SqlSourceType
        {
            Oracle,
            MSSql,
            MySql,
            SQLite
        }
    }

    再创建IDBHelp接口:

    /********************************************************************************
    ** Class Name:   IDBHelp
    ** Author:      Spring Yang
    ** Create date: 2013-3-16
    ** Modify:      Spring Yang
    ** Modify Date: 2013-3-16
    ** Summary:     IDBHelp interface
    *********************************************************************************/
    
    namespace BlogDBHelp
    {
        using System.Collections.Generic;
        using System.Data;
        using System.Data.Common;
    
        public interface IDBHelp
        {
            /// <summary>
            /// Gets the connection string
            /// </summary>
            string ConnectionString { get; set; }
    
            /// <summary>
            /// Gets or sets the max connection count
            /// </summary>
            int MaxConnectionCount { get; set; }
    
            /// <summary>
            /// Gets or sets the sql source type
            /// </summary>
            SqlSourceType DataSqlSourceType { get; }
    
            /// <summary>
            /// Execute query by stored procedure 
            /// </summary>
            /// <param name="cmdText">stored procedure</param>
            /// <returns>DataSet</returns>
            DataSet ExecuteQuery(string cmdText);
     
            /// <summary>
            /// Execute non query by stored procedure and parameter list
            /// </summary>
            /// <param name="cmdText">stored procedure</param>
            /// <returns>execute count</returns>
            int ExecuteNonQuery(string cmdText);
     
            /// <summary>
            /// Execute scalar by store procedure
            /// </summary>
            /// <param name="cmdText">store procedure</param>
            /// <returns>return value</returns>
            object ExecuteScalar(string cmdText);
    
            /// <summary>
            /// Get data base parameter by parameter name and parameter value
            /// </summary>
            /// <param name="key">parameter name</param>
            /// <param name="value">parameter value</param>
            /// <returns>sql parameter</returns>
            DbParameter GetDbParameter(string key, object value);
    
            /// <summary>
            /// Get data base parameter by parameter name and parameter value
            /// and parameter direction 
            /// </summary>
            /// <param name="key">parameter name</param>
            /// <param name="value">parameter value</param>
            /// <param name="direction">parameter direction </param>
            /// <returns>data base parameter</returns>
            DbParameter GetDbParameter(string key, object value, ParameterDirection direction);
    
            /// <summary>
            /// Read entity list by  store procedure
            /// </summary>
            /// <typeparam name="T">entity</typeparam>
            /// <param name="cmdText">store procedure</param>
            /// <returns>entity list</returns>
            List<T> ReadEntityList<T>(string cmdText) where T : new();
     
            /// <summary>
            /// Get dictionary result by store procedure and parameters and string list
            /// </summary>
            /// <param name="cmdText">store procedure</param>
            /// <param name="stringlist">string list</param>
            /// <returns>result list</returns>
            List<Dictionary<string, object>> GetDictionaryList(string cmdText,
                                                               List<string> stringlist);
    
            /// <summary>
            /// Batch execute ExecuteNonQuery by cmdText list
            /// </summary>
            /// <param name="cmdList">cmd text list</param>
            /// <returns>execute true or not</returns>
            bool BatchExecuteNonQuery(List<string> cmdList);
    
        }
    }

    再创建AbstractDBHelp 抽象类:

    /********************************************************************************
    ** Class Name:   AbstractDBHelp
    ** Author:      Spring Yang
    ** Create date: 2013-3-16
    ** Modify:      Spring Yang
    ** Modify Date: 2013-3-16
    ** Summary:     AbstractDBHelp interface
    *********************************************************************************/
    
    namespace BlogDBHelp
    {
        using System;
        using System.Collections.Generic;
        using System.Configuration;
        using System.Data;
        using System.Data.Common;
        using System.Reflection;
        using System.Threading;
    
        public abstract class AbstractDBHelp : IDBHelp
        {
            #region Private Property
    
            private static int _currentCount;
    
            private int _maxConnectionCount;
    
            private string _connectionString;
    
            #endregion
    
            #region Private Methods
    
            private void AddConnection()
            {
                if (_currentCount < MaxConnectionCount)
                    _currentCount++;
                else
                {
                    while (true)
                    {
                        Thread.Sleep(5);
                        if (_currentCount < MaxConnectionCount)
                        {
                            _currentCount++;
                            break;
                        }
                    }
                }
            }
    
            private void RemoveConnection()
            {
                _currentCount--;
            }
    
    
            /// <summary>
            /// Execute query by stored procedure and parameter list
            /// </summary>
            /// <param name="cmdText">stored procedure and parameter list</param>
            /// <param name="parameters">parameter list</param>
            /// <returns>DataSet</returns>
            private DataSet ExecuteQuery(string cmdText, List<DbParameter> parameters)
            {
                using (var conn = GetConnection(ConnectionString))
                {
                    conn.Open();
                    using (var command = conn.CreateCommand())
                    {
                        var ds = new DataSet();
                        PrepareCommand(command, conn, cmdText, parameters);
                        var da = GetDataAdapter(command);
                        da.Fill(ds);
                        return ds;
                    }
                }
            }
    
    
            /// <summary>
            /// Execute non query by stored procedure and parameter list
            /// </summary>
            /// <param name="cmdText">stored procedure</param>
            /// <param name="parameters">parameter list</param>
            /// <returns>execute count</returns>
            private int ExecuteNonQuery(string cmdText, List<DbParameter> parameters)
            {
                using (var conn = GetConnection(ConnectionString))
                {
                    conn.Open();
                    using (var command = conn.CreateCommand())
                    {
                        PrepareCommand(command, conn, cmdText, parameters);
                        return command.ExecuteNonQuery();
                    }
                }
            }
    
            public bool BatchExecuteNonQuery(List<string> cmdList)
            {
                using (var conn = GetConnection(ConnectionString))
                {
                    conn.Open();
                    using (var transaction = conn.BeginTransaction())
                    {
                        foreach (var cmdText in cmdList)
                        {
                            if (string.IsNullOrEmpty(cmdText)) continue;
                            using (var command = conn.CreateCommand())
                            {
                                try
                                {
                                    command.CommandText = cmdText;
                                    command.Transaction = transaction;
                                    command.ExecuteNonQuery();
                                }
                                finally
                                {
                                    command.CommandText = null;
                                    command.Dispose();
                                }
                            }
                        }
                        try
                        {
                            transaction.Commit();
                            return true;
                        }
                        catch
                        {
                            transaction.Rollback();
                            return false;
                        }
                        finally
                        {
                            transaction.Dispose();
                            conn.Dispose();
                            conn.Close();
                            cmdList.Clear();
                        }
                    }
                }
    
            }
    
            /// <summary>
            /// Execute reader by store procedure and parameter list
            /// </summary>
            /// <param name="cmdText">store procedure</param>
            /// <param name="parameters">parameter list</param>
            /// <param name="conn">database connection </param>
            /// <returns>data reader</returns>
            public DbDataReader ExecuteReader(string cmdText, List<DbParameter> parameters, out DbConnection conn)
            {
                conn = GetConnection(ConnectionString);
                conn.Open();
                AddConnection();
                var command = conn.CreateCommand();
                PrepareCommand(command, conn, cmdText, parameters);
                var dataReader = command.ExecuteReader();
                RemoveConnection();
                return dataReader;
            }
    
            /// <summary>
            /// Execute reader by store procedure and parameter list
            /// </summary>
            /// <param name="cmdText">store procedure</param>
            /// <param name="parameters">parameter list</param>
            /// <returns>data reader</returns> 
            private List<T> ReadEntityList<T>(string cmdText, List<DbParameter> parameters) where T : new()
            {
                using (var conn = GetConnection(ConnectionString))
                {
                    conn.Open();
                    using (var command = conn.CreateCommand())
                    {
                        PrepareCommand(command, conn, cmdText, parameters);
                        var dataReader = command.ExecuteReader();
                        return ReadEntityListByReader<T>(dataReader);
                    }
                }
            }
    
            /// <summary>
            /// Read entity list by reader
            /// </summary>
            /// <typeparam name="T">entity</typeparam>
            /// <param name="reader">data reader</param>
            /// <returns>entity</returns>
            private List<T> ReadEntityListByReader<T>(DbDataReader reader) where T : new()
            {
                var listT = new List<T>();
                using (reader)
                {
                    while (reader.Read())
                    {
                        var fileNames = new List<string>();
                        for (int i = 0; i < reader.VisibleFieldCount; i++)
                        {
                            fileNames.Add(reader.GetName(i));
                        }
                        var inst = new T();
                        foreach (var pi in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
                        {
                            if (!fileNames.Exists(fileName => string.Compare(fileName, pi.Name, StringComparison.OrdinalIgnoreCase) == 0))
                                continue;
                            object obj;
                            try
                            {
                                obj = reader[pi.Name];
                            }
                            catch (Exception)
                            {
                                continue;
                            }
    
                            if (obj == DBNull.Value || obj == null)
                                continue;
                            var si = pi.GetSetMethod();
                            if (si == null)
                                continue;
                            if (pi.PropertyType == typeof(bool?))
                                pi.SetValue(inst, Convert.ToBoolean(obj), null);
                            else if (pi.PropertyType == typeof(string))
                                pi.SetValue(inst, obj.ToString(), null);
                            else if (pi.PropertyType == typeof(Int32))
                                pi.SetValue(inst, Convert.ToInt32(obj), null);
                            else if (pi.PropertyType == typeof(Int64))
                                pi.SetValue(inst, Convert.ToInt64(obj), null);
                            else if (pi.PropertyType == typeof(decimal))
                                pi.SetValue(inst, Convert.ToDecimal(obj), null);
                            else
                                pi.SetValue(inst, obj, null);
                        }
                        listT.Add(inst);
                    }
                }
                return listT;
            }
    
            /// <summary>
            /// Get Dictionary list by string list
            /// </summary>
            /// <param name="cmdText">Store procedure</param>
            /// <param name="parameters">parameter list</param>
            /// <param name="stringlist">string list</param>
            /// <returns>result list</returns>
            private List<Dictionary<string, object>> GetDictionaryList(string cmdText, List<DbParameter> parameters, List<string> stringlist)
            {
                using (var conn = GetConnection(ConnectionString))
                {
                    AddConnection();
                    using (var command = conn.CreateCommand())
                    {
                        PrepareCommand(command, conn, cmdText, parameters);
                        var dataReader = command.ExecuteReader();
                        RemoveConnection();
                        return ReadStringListByReader(dataReader, stringlist);
                    }
                }
            }
    
    
    
    
            /// <summary>
            /// Read dictionary list by reader and string list
            /// </summary>
            /// <param name="reader">Db data reader</param>
            /// <param name="stringlist">string</param>
            /// <returns>result list</returns>
            private List<Dictionary<string, object>> ReadStringListByReader(DbDataReader reader, List<string> stringlist)
            {
                var listResult = new List<Dictionary<string, object>>();
                using (reader)
                {
                    while (reader.Read())
                    {
                        var dicResult = new Dictionary<string, object>();
                        foreach (var key in stringlist)
                        {
                            if (!stringlist.Exists(fileName => string.Compare(fileName, key, StringComparison.OrdinalIgnoreCase) == 0))
                                continue;
                            object obj;
                            try
                            {
                                obj = reader[key];
                            }
                            catch (Exception)
                            {
                                continue;
                            }
                            if (obj == DBNull.Value || obj == null)
                                continue;
                            dicResult.Add(key, obj);
                        }
                        listResult.Add(dicResult);
                    }
                }
                return listResult;
            }
    
    
            /// <summary>
            /// Execute scalar by store procedure and parameter list
            /// </summary>
            /// <param name="cmdText">store procedure</param>
            /// <param name="parameters">parameter list</param>
            /// <returns>return value</returns>
            private object ExecuteScalar(string cmdText, List<DbParameter> parameters)
            {
                using (var conn = GetConnection(ConnectionString))
                {
                    conn.Open();
                    using (var command = conn.CreateCommand())
                    {
                        PrepareCommand(command, conn, cmdText, parameters);
                        return command.ExecuteScalar();
                    }
                }
            }
    
            /// <summary>
            /// Prepare the execute command
            /// </summary>
            /// <param name="cmd">my sql command</param>
            /// <param name="conn">my sql connection</param>
            /// <param name="cmdText">stored procedure</param>
            /// <param name="parameters">parameter list</param>
            private void PrepareCommand(DbCommand cmd, DbConnection conn, string cmdText, List<DbParameter> parameters)
            {
                if (conn.State != ConnectionState.Open)
                    conn.Open();
                cmd.Parameters.Clear();
                cmd.Connection = conn;
                cmd.CommandText = cmdText;
    
                cmd.CommandType = CommandType.Text;
                cmd.CommandTimeout = 30;
                if (parameters != null)
                    foreach (var parameter in parameters)
                    {
                        cmd.Parameters.Add(parameter);
                    }
            }
    
            #endregion
    
            #region Public Property
    
            public int MaxConnectionCount
            {
                get
                {
                    if (_maxConnectionCount <= 0)
                        _maxConnectionCount = 100;
                    return _maxConnectionCount;
                }
                set { _maxConnectionCount = value; }
            }
    
            public abstract SqlSourceType DataSqlSourceType { get; }
    
            #endregion
    
            #region Protected Method
    
    
            protected abstract DbDataAdapter GetDataAdapter(DbCommand command);
    
            protected abstract DbConnection GetConnection(string connectionString);
    
            #endregion
    
            #region Public Methods
    
            /// <summary>
            /// Gets the connection string
            /// </summary>
            public string ConnectionString
            {
                get
                {
                    if (_connectionString == null)
                        _connectionString = ConfigurationManager.ConnectionStrings[""].ConnectionString;
                    return _connectionString;
                }
                set { _connectionString = value; }
            }
    
            /// <summary>
            /// Execute query by stored procedure and parameter list
            /// </summary>
            /// <param name="cmdText">stored procedure and parameter list</param>
            /// <returns>DataSet</returns>
            public DataSet ExecuteQuery(string cmdText)
            {
                try
                {
                    AddConnection();
                    return ExecuteQuery(cmdText, new List<DbParameter>());
                }
                finally
                {
                    RemoveConnection();
                }
    
            }
    
     
    
     
    
            /// <summary>
            /// Execute non query by stored procedure and parameter list
            /// </summary>
            /// <param name="cmdText">stored procedure</param>
            /// <returns>execute count</returns>
            public int ExecuteNonQuery(string cmdText)
            {
                try
                {
                    AddConnection();
                    return ExecuteNonQuery(cmdText, new List<DbParameter>());
                }
                finally
                {
                    RemoveConnection();
                }
            }
    
            /// <summary>
            /// Execute scalar by store procedure and parameter list
            /// </summary>
            /// <param name="cmdText">store procedure</param>
            /// <returns>return value</returns>
            public object ExecuteScalar(string cmdText)
            {
                try
                {
                    AddConnection();
                    return ExecuteScalar(cmdText, new List<DbParameter>());
                }
                finally
                {
                    RemoveConnection();
                }
            }
    
     
            /// <summary>
            /// Get data base parameter by parameter name and parameter value
            /// </summary>
            /// <param name="key">parameter name</param>
            /// <param name="value">parameter value</param>
            /// <returns>my sql parameter</returns>
            public abstract DbParameter GetDbParameter(string key, object value);
    
            /// <summary>
            /// Get data base parameter by parameter name and parameter value
            /// and parameter direction 
            /// </summary>
            /// <param name="key">parameter name</param>
            /// <param name="value">parameter value</param>
            /// <param name="direction">parameter direction </param>
            /// <returns>data base parameter</returns>
            public DbParameter GetDbParameter(string key, object value, ParameterDirection direction)
            {
                var parameter = GetDbParameter(key, value);
                parameter.Direction = direction;
                return parameter;
            }
    
            /// <summary>
            /// Get Dictionary list by string list
            /// </summary>
            /// <param name="cmdText">Store procedure</param>
            /// <param name="stringlist">string list</param>
            /// <returns>result list</returns>
            public List<Dictionary<string, object>> GetDictionaryList(string cmdText, List<string> stringlist)
            {
                return GetDictionaryList(cmdText, new List<DbParameter>(), stringlist);
            }
    
            /// <summary>
            /// Execute reader by store procedure
            /// </summary>
            /// <param name="cmdText">store procedure</param>
            /// <returns>data reader</returns> 
            public List<T> ReadEntityList<T>(string cmdText) where T : new()
            {
                try
                {
                    AddConnection();
                    return ReadEntityList<T>(cmdText, new List<DbParameter>());
                }
                finally
                {
                    RemoveConnection();
                }
            }
     
            #endregion
        }
    }

    再创建MSSqlHelp 类:

    /********************************************************************************
    ** Class Name:   MySqlHelp
    ** Author:      Spring Yang
    ** Create date: 2013-3-16
    ** Modify:      Spring Yang
    ** Modify Date: 2013-3-16
    ** Summary:     MySqlHelp class
    *********************************************************************************/
    
    namespace BlogDBHelp
    {
        using System.Data.Common;
        using System.Data.SqlClient;
    
        public class MSSqlHelp : AbstractDBHelp
        {
            #region Protected Method
    
            protected override DbDataAdapter GetDataAdapter(DbCommand command)
            {
                return new SqlDataAdapter(command as SqlCommand);
            }
    
            protected override DbConnection GetConnection(string connectionString)
            {
                return new SqlConnection(connectionString);
            }
    
            #endregion
    
            #region Public Mehtod
    
            public override SqlSourceType DataSqlSourceType
            {
                get { return SqlSourceType.MSSql; }
            }
    
            public override DbParameter GetDbParameter(string key, object value)
            {
                return new SqlParameter(key, value);
            }
     
            #endregion
        }
    }

    再创建MySqlHelp类

    /********************************************************************************
    ** Class Name:   MySqlHelp
    ** Author:      Spring Yang
    ** Create date: 2013-3-16
    ** Modify:      Spring Yang
    ** Modify Date: 2013-3-16
    ** Summary:     MySqlHelp class
    *********************************************************************************/
    
    namespace BlogDBHelp
    {
        using System.Data.Common;
        using MySql.Data.MySqlClient;
    
        public class MySqlHelp : AbstractDBHelp
        {
            #region Protected Method
    
            protected override DbDataAdapter GetDataAdapter(DbCommand command)
            {
                return new MySqlDataAdapter();
            }
    
            protected override DbConnection GetConnection(string connectionString)
            {
                return new MySqlConnection(connectionString);
            }
    
            #endregion
    
            #region Public Mehtod
    
            public override DbParameter GetDbParameter(string key, object value)
            {
                return new MySqlParameter(key, value);
            }
     
            public override SqlSourceType DataSqlSourceType
            {
                get { return SqlSourceType.MySql; }
            }
    
            #endregion
    
        }
    }

    再创建OracleHelp类:

    /********************************************************************************
    ** Class Name:   OracleHelp
    ** Author:      Spring Yang
    ** Create date: 2013-3-16
    ** Modify:      Spring Yang
    ** Modify Date: 2013-3-16
    ** Summary:     OracleHelp class
    *********************************************************************************/
    
    namespace BlogDBHelp
    {
        using System.Data.Common;
        using Oracle.DataAccess.Client;
    
        public class OracleHelp : AbstractDBHelp
        {
            #region Protected Method
    
            protected override DbDataAdapter GetDataAdapter(DbCommand command)
            {
                return new OracleDataAdapter(command as OracleCommand);
            }
    
            protected override DbConnection GetConnection(string connectionString)
            {
                return new OracleConnection(connectionString);
            }
    
            #endregion
    
            #region Public Mehtod
    
            public override DbParameter GetDbParameter(string key, object value)
            {
                return new OracleParameter(key, value);
            }
    
            public override SqlSourceType DataSqlSourceType
            {
                get { return SqlSourceType.Oracle; }
            }
    
            #endregion
        }
    }

    再创建SQLiteHelp类:

    /********************************************************************************
    ** Class Name:   SQLiteHelp
    ** Author:      Spring Yang
    ** Create date: 2013-3-16
    ** Modify:      Spring Yang
    ** Modify Date: 2013-3-16
    ** Summary:     SQLiteHelp class
    *********************************************************************************/
    
    namespace BlogDBHelp
    {
        using System.Data.Common;
        using System.Data.SQLite;
    
        public class SQLiteHelp : AbstractDBHelp
        {
            #region Protected Method
    
            protected override DbDataAdapter GetDataAdapter(DbCommand command)
            {
                return new SQLiteDataAdapter(command as SQLiteCommand);
            }
    
            protected override DbConnection GetConnection(string connectionString)
            {
                return new SQLiteConnection(connectionString);
            }
    
            #endregion
    
            #region Public Mehtod
    
            public override DbParameter GetDbParameter(string key, object value)
            {
                return new SQLiteParameter(key, value);
            }
     
            public override SqlSourceType DataSqlSourceType
            {
                get { return SqlSourceType.SQLite; }
            }
    
            #endregion
        }
    }

    仔细观察上面代码,发现每增加一种数据库的支持,我们只需实现几个特有抽象方法就可以了,而调用只需像如下就可以了。

    IDBHelp  _dbHelpInstance = new SQLiteHelp
                        {
                            ConnectionString ="";    };

    欢迎各位参与讨论,如果觉得对你有帮助,请点击image    推荐下,万分谢谢.

    作者:spring yang

    出处:http://www.cnblogs.com/springyangwc/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    常用cmd命令总结
    百度地图api的简单应用(二):轻量级路径规划
    百度地图api的简单应用(一):POI检索
    R语言-八皇后问题
    8086基本IO口的仿真
    输入输出与中断
    汇编语言例子
    变量标号
    变量声明
    串操作指令2
  • 原文地址:https://www.cnblogs.com/springyangwc/p/2964428.html
Copyright © 2020-2023  润新知