在 .NET 的学习过程中用过三种数据库:Sql Server、Access、SQLite。Sql Server 用得相对多一点点,但是,麻烦,每次用它都需要开服务,而且还费资源,更麻烦的是拷贝到一台没有装SqlServer的电脑上还不能用,所以一般练习中只要不涉及到什么存储过程这些也基本不用它。Access简单的文件型数据库,office的套件,基本的SQL语句也支持,在一般的小型应用系统中用起来还行,而且在Windows 7开始操作系统中就已经内置了Access的服务,随便拷贝。SQLite用过一次,需要安装服务,和Access一样,拷贝一下就可以用,就是管理工具的界面比较shit。

用过三种数据库后,发现其实在微软的ADO.NET中操作数据库的方式是一样的,链接对象都是继承自实现了IDbConnection接口的抽象类DbConnection,以及实现了IDbCommand的接口的抽象类DbCommand,其它的都一样。古就可以统一用接口或者抽象来来进行操作数据库了,这样就能够实现基本的跨数据库访问的功能了。唯一不同的就是实例化连接字符串的时候要用具体的子类来进行实例化,这时就可以用静态工厂来实现,从而做到不修改程序就实现夸数据库的功能,当然应用程序中的SQL语句是通用的才行,如果是某些数据库特有的,那就不行了。

静态工厂

也成为简单工厂,主要是用来因对对象的变化,根据不同的要求创建不同的实例,就可以进行一个不同的操作。在黑马的基础加强里面,有一个比较经典的例子能够说明他的作用:简单计算器。主程序中一直不变,变的是运算规则,然后把运算规则给抽出来,写到一个工厂中,然后根据不同的运算符来创建不同的计算实例,然后用一个同一的接口返回这个实例对象,就能够完成计算了。

         /// <summary>
/// 根据传递过来的运算符,来创造不同的子类对象
/// </summary>
/// <param name="op">运算符</param>
/// <returns>返回的是一个实现了接口ICalculatorable.ICalculable的子类对象</returns>
public static ICalculatorable.ICalculable CreatInstance (string op)
{
//创建一个接口变量,赋值为null
ICalculatorable.ICalculable cc = null;
////根据传递过来的运算符来创建对应的实例成员
switch (op)
{
//如果传递过来的是加法运算符,就创建一个计算加法的实例成员,并且赋值给上面的接口变量
case "+": cc = new AddLib_02.Add(); break;
case "-": cc = new SubLib_02.Sub(); break;
case "*": cc = new MultipLib_02.Multip(); break;
case "/": cc = new DivLib_02.Div(); break;
case "%": cc = new ModelLib_02.Model(); break;
//若上面的都不符合,就将接口变量赋值为null
default: cc = null;
break;
}
//返回指向了一个具体实例对象的接口变量
return cc;
}

简单计算器的静态工厂

其实在访问数据库的时候也是一样的,唯一变的就是链接实例,所以就可以把创建实例的东西给抽出来,交给一个工厂来实现,工厂可以通过读取配置文件来进行创建相应的实例对象,然后返回。代码如下:

     internal sealed class DbProvideFactory
{
private static string dbProvide = ConfigurationManager.AppSettings["provide"];
public static string DbProvide { get { return dbProvide; } } private static string connectionString = ConfigurationManager.ConnectionStrings["connStr"].ConnectionString;
/// <summary>
/// 连接字符串
/// </summary>
public static string ConnectionString
{
get { return connectionString; }
private set { connectionString = value; }
} #region 返回一个连接对象
public static DbConnection GetConnection ()
{
switch (dbProvide.ToLower())
{
case "sqlserver":
case "sql":
case "mssqlserver":
case "mssql": return new SqlConnection(connectionString);
case "access": return new OleDbConnection(connectionString);
case "sqlite": return new SQLiteConnection(connectionString);
case "oracle": return new OracleConnection(connectionString);
default: return new SqlConnection(connectionString);
}
}
#endregion #region 返回一个 Adapter
/// <summary>
/// 返回一个 Adapter
/// </summary>
/// <param name="cmd">Command 命令</param>
/// <returns></returns>
public static DataAdapter GetAdapter (IDbCommand cmd)
{
switch (dbProvide.ToLower())
{
case "sqlserver":
case "sql":
case "mssqlserver":
case "mssql": return new SqlDataAdapter(cmd as SqlCommand);
case "access": return new OleDbDataAdapter(cmd as OleDbCommand);
case "sqlite": return new SQLiteDataAdapter(cmd as SQLiteCommand);
case "oracle": return new OracleDataAdapter(cmd as OracleCommand);
default: return new SqlDataAdapter(cmd as SqlCommand);
}
}
#endregion #region 生成参数化查询时的参数对象
/// <summary>
/// 生成参数化查询时的参数对象
/// </summary>
/// <param name="name">参数名,@符号可有可无</param>
///
/// <returns></returns>
public static DbParameter GetParameter (string name, object value)
{
if (!name.StartsWith("@"))
{
name = "@" + name;
}
if (value == null)
{
value = DBNull.Value;
}
switch (dbProvide.ToLower())
{
case "sqlserver":
case "sql":
case "mssqlserver":
case "mssql": return new SqlParameter(name, value);
case "access": return new OleDbParameter(name, value);
case "sqlite": return new SQLiteParameter(name, value);
case "oracle": return new OracleParameter(name, value);
default: return new SqlParameter(name, value);
}
} /// <summary>
/// 生成参数化查询时的 输出参数
/// </summary>
/// <param name="name">参数名</param>
/// <param name="type">参数类型</param>
/// <returns></returns>
public static IDbDataParameter GetParameter (string name,DbType type)
{
if (!name.StartsWith("@"))
{
name = "@" + name;
}
IDbDataParameter p;
switch (dbProvide.ToLower())
{
case "sqlserver":
case "sql":
case "mssqlserver":
case "mssql": p = new SqlParameter(name, type); break;
case "access": p = new OleDbParameter(name, type); break;
case "sqlite": p = new SQLiteParameter(name, type); break;
case "oracle": p = new OracleParameter(name, type); break;
default: p = new SqlParameter(name, type); break;
}
p.Direction = ParameterDirection.Output;
return p;
}
#endregion
}

上面代码中首先读取了配置文件,以及连接字符串,这点可能封装的是太好,按理说,应该从DbHelper中传递过来,但是考虑到后面多处用到它,就把他放到这个地方了。
    根据配置文件中数据提供者的值不同然后创建不同的数据库连接对象。同时由于在参数化查询的时候,需要实例化参数对象,有封装了两个参数对象方法。在用SqlServer的存储过程中,考虑到有输出参数,古做了一个重载。

至于 DataAdapter,由于它里也是可以自己创建连接的,所以也就比较麻烦一点,手动创建了,其实可以利用微软已经提供好的一种方式,就是通过读取配置文件中的配置提供者,然后调用一些方法来进行创建,实现原理中应该也是利用的反射,由于这个值在配置文件中比较麻烦,需要写全称,也就放弃它了。

上面基本上就是利用简单工厂来实现的创建不同数据库实例和参数化对象的方式。

  

SQLite需要在官方下载ADO.NET的插件,然后进行引用,Oracle数据库没有尝试过,也需要应用组件,列在此处也是为了以后方便扩展

DbHelper

这里面就封装了几个常规的增删改查的方法,调用工厂的方法得到连接对象和参数,然后用接口去指向他们,由于使用的是接口去指向,故在添加参数的时候,只能够通过遍历来实现,可以改为抽象类来指向,这样就能够一次添加一个数组了。代码如下:

 public partial class DbHelper
{
//#region 得到一个连接对象,由具体的子类去重写而实现
///// <summary>
///// 得到一个连接对象,由具体的子类去重写而实现
///// </summary>
///// <returns></returns>
//public abstruct DbConnection GetConnection ();
//#endregion #region 执行增加、删除、更新三个非查询语句
public static int ExecuteNonQuery (string strSql, params IDataParameter[] pars)
{
using (IDbConnection conn = DbProvideFactory.GetConnection() )
{
using (IDbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = strSql; if (pars != null && pars.Length > )
{
foreach (var item in pars)
{
cmd.Parameters.Add(item);
}
}
conn.Open();
return cmd.ExecuteNonQuery();
}
}
}
#endregion #region 执行标量值查询
public static object ExecuteScalar (string strSql, params IDataParameter[] pars)
{
using (IDbConnection conn = DbProvideFactory.GetConnection())
{
using (IDbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = strSql;
if (pars != null && pars.Length > )
{
foreach (var item in pars)
{
cmd.Parameters.Add(item);
}
}
conn.Open();
return cmd.ExecuteScalar();
}
}
}
#endregion #region 返回一个只读的DbDataReader
public static IDataReader ExecuteReader (string strSql,CommandType type, params IDataParameter[] pars)
{
IDbConnection conn = DbProvideFactory.GetConnection(); using (IDbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = strSql;
if (pars != null && pars.Length > )
{
foreach (var item in pars)
{
cmd.Parameters.Add(item);
}
}
cmd.CommandType = type;
try
{
conn.Open();
//外部关闭当前连接
return cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
}
catch
{
conn.Close();
conn.Dispose();
throw;
}
}
}
#endregion #region 返回一张数据表格,如果没有查到数据就返回null
//由于用的是接口(或者抽象类)不能够直接创建Command来添加参数,所以调用了工厂的方法创建一个连接对象,然后创建Command来实现参数的添加
public static DataTable DataAdpater (string strSql, params IDataParameter[] pars)
{
using (IDbConnection conn = DbProvideFactory.GetConnection())
{
IDbCommand cmd = conn.CreateCommand();
cmd.CommandText = strSql;
if (pars != null && pars.Length > )
{
foreach (var item in pars)
{
cmd.Parameters.Add(item);
}
}
IDataAdapter adapter = DbProvideFactory.GetAdapter(cmd);
DataSet set = new DataSet();
int count = adapter.Fill(set);
return count > ? set.Tables[] : null;
}
}
#endregion #region 将一个SqlDataReader对象转换成一个实体类对象 +static TEntity MapEntity<TEntity>(SqlDataReader reader) where TEntity : class,new()
/// <summary>
/// 将一个DataReader对象转换成一个实体类对象
/// </summary>
/// <typeparam name="TEntity">实体类型</typeparam>
/// <param name="reader">当前指向的reader</param>
/// <returns>实体对象</returns>
public static TEntity MapEntity<TEntity>(IDataReader reader) where TEntity : class,new()
{
try
{
var props = typeof(TEntity).GetProperties();
var entity = new TEntity();
foreach (var prop in props)
{
if (prop.CanWrite)
{
try
{
var index = reader.GetOrdinal(prop.Name);
var data = reader.GetValue(index);
if (data != DBNull.Value)
{
prop.SetValue(entity, Convert.ChangeType(data, prop.PropertyType), null);
}
}
catch (IndexOutOfRangeException)
{
continue;
}
}
}
return entity;
}
catch
{
return null;
}
}
#endregion
}

在上面代码中,如果程序需要使用具体的连接对象,可以将DBHelper改成一个抽象类,然后把创建连接实例对象改成抽象方法,就可以了。

通过上面的简单工厂和用接口来指向操作数据库的各种对象就能够做到简单的跨数据库的功能了

静态工厂 + DbHelper的更多相关文章

  1. 静态工厂方法VS构造器

    我之前已经介绍过关于构建者模式(Builder Pattern)的一些内容,它是一种很有用的模式用于实例化包含几个属性(可选的)的类,带来的好处是更容易读.写及维护客户端代码.今天,我将继续介绍对象创 ...

  2. [原创]java WEB学习笔记102:Spring学习---Spring Bean配置:bean配置方式(工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean) 全类名

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  3. Spring 学习总结 使用静态工厂创建Bean

    创建Bean时,class属性必须指定,此时为静态工厂类. factory-method指定静态工厂方法名. 接口: public interface Being { public void test ...

  4. 【Effective Java】1、静态工厂的方式代替构造函数

    使用一个服提供者对进行服务的提供,服务的请求通过不同的提供者提供不同的服务,服务提供者首先必须在工厂中进行注册,然后才可以通过工厂实例化服务 Service.java package cn.xf.cp ...

  5. 读Effective Java笔记之one:static Factory methods instead of Constructors (静态工厂方与构造器)

    获取类的实例的方法有很多种,在这很多种方法中,它们各有优缺,各有特点.这里,只介绍2中方法 1.使用构造方法 public class Person { private String sex; /** ...

  6. <创建和销毁对象>经验法则——考虑用静态工厂方法代替公有构造方法

    一.引出静态工厂方法 对于java类而言,为了让使用者获取它自身的一个实例化对象,会有以下方法: 1.该类提供一个公有的构造方法.在这种情况下,程序可以通过多个“new 构造方法”语句来创建类的任意多 ...

  7. HttpSolrServer-采用静态工厂方法,创建HttpSolrServer单实例

    HttpSolrServer线程安全,如果使用下面构造器,必须对所有的请求重用相同的实例.如果实例在运行中创建的,它可能会导致连接泄漏.推荐的做法就是保持每个solr服务url的HttpSolrSer ...

  8. 创建对象_工厂方法(Factory Method)模式 与 静态工厂方法

      工厂方法模式:   定义:为创建对象定义一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟至子类.   应用场景: 客户类不关心使用哪个具体类,只关心该接口所提供的功能: 创建过程比较 ...

  9. 设计模式系列 1——StaticFactory(静态工厂),AbstractFactory(抽象工厂)

    本文出自 代码大湿 代码大湿 本系列持续更新,敬请关注. 1 静态工厂 静态工厂介绍: 静态工厂模式可以实现接口封装隔离的原则.在客户端只知接口而不知实现的时候可以使用静态工厂模式. 源码请点击我 角 ...

随机推荐

  1. 关于部署传统的Dynamic Web项目

    现在大部分都是采用maven构建的项目,但是偶尔也会遇到一些较老的项目,采用的是传统的动态Web项目. 我最近碰到这样一个项目,项目用的jar包都放在了WEB-INF/lib目录下.之前的人采用的部署 ...

  2. SparkStreaming 监控文件目录

    SparkStream 监控文件目录时,只能监控文件内是否添加新的文件,如果文件名没有改变只是文件内容改变,那么不会检测出有文件进行了添加. )) )).reduceByKey(_ + _) word ...

  3. 20155312 张竞予 2006-2007-2 《Java程序设计》第四周学习总结

    20155312 2006-2007-2 <Java程序设计>第四周学习总结 课堂笔记 Ctrl+shift+T调出三个窗口,分别是"vi编写代码","jav ...

  4. fmt标签如何计算两个日期之间相隔的天数

    <h2>start -- ${start}</h2><h2>end -- ${end}</h2><fmt:formatDate var=" ...

  5. 用 ASP.NET MVC 实现基于 XMLHttpRequest long polling(长轮询) 的 Comet(转)

    轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 优点:后端程序编写比较容易. 缺点:请求中有大半是无用,浪费带宽和服务器资源. 实例:适于小型应用. 长轮询:客 ...

  6. zookeeper 单机集成部署

    概述 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等,是很多分布式的基础设置,比如dubbo,k ...

  7. ES6展开运算符的3个用法

    展开运算符的用法1:传参 // 展开运算符的用法1 : 传参 function test(a,b) { return a + b ; } var arr = [1,2]; console.log(te ...

  8. Win7 VS2015环境使用qt-msvc2015-5.6.0

    QT下载 http://www.qt.io/download-open-source/#section-2 我用的是 qt-opensource-windows-x86-msvc2015-5.6.0. ...

  9. php输出语句

    看不懂? 抄一遍代码吧. echo 和 print 在 PHP 中有两个基本的输出方式: echo 和 print echo 和 print 区别: echo - 可以输出一个或多个字符串 print ...

  10. Andorid第一次作业

    一.作业截图 二.项目路径 https://git.coding.net/bestimbalance/Android.git 三.小组成员 邢路:  https://www.cnblogs.com/x ...