策略模式实现支持多种类数据库的DBHelp
策略模式实现支持多种类数据库的DBHelp
概述
需求
有时我们的系统需要支持多种数据库,如即要支持MSSQL server又要同时支持Oracle database.而如果我们为些实现两套数据库操作的方式,就会不能很好的达到软件设计的目标:高内聚,低偶合。
设计
采取策略模式(Strategy),它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。
优点:
1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点:
1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)
DBHelp设计目标,同时支持Sqlite、Oracle 、MySql 、MsSql,类UML图设计如下:
有了上面的设计图如后,我们先创建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 =""; };
欢迎各位参与讨论,如果觉得对你有帮助,请点击 推荐下,万分谢谢.
作者: spring yang
出处: http://www.cnblogs.com/springyangwc/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于策略模式实现支持多种类数据库的DBHelp的详细内容...