静态工厂 + DbHelper
在 .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的更多相关文章
- 静态工厂方法VS构造器
我之前已经介绍过关于构建者模式(Builder Pattern)的一些内容,它是一种很有用的模式用于实例化包含几个属性(可选的)的类,带来的好处是更容易读.写及维护客户端代码.今天,我将继续介绍对象创 ...
- [原创]java WEB学习笔记102:Spring学习---Spring Bean配置:bean配置方式(工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean) 全类名
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Spring 学习总结 使用静态工厂创建Bean
创建Bean时,class属性必须指定,此时为静态工厂类. factory-method指定静态工厂方法名. 接口: public interface Being { public void test ...
- 【Effective Java】1、静态工厂的方式代替构造函数
使用一个服提供者对进行服务的提供,服务的请求通过不同的提供者提供不同的服务,服务提供者首先必须在工厂中进行注册,然后才可以通过工厂实例化服务 Service.java package cn.xf.cp ...
- 读Effective Java笔记之one:static Factory methods instead of Constructors (静态工厂方与构造器)
获取类的实例的方法有很多种,在这很多种方法中,它们各有优缺,各有特点.这里,只介绍2中方法 1.使用构造方法 public class Person { private String sex; /** ...
- <创建和销毁对象>经验法则——考虑用静态工厂方法代替公有构造方法
一.引出静态工厂方法 对于java类而言,为了让使用者获取它自身的一个实例化对象,会有以下方法: 1.该类提供一个公有的构造方法.在这种情况下,程序可以通过多个“new 构造方法”语句来创建类的任意多 ...
- HttpSolrServer-采用静态工厂方法,创建HttpSolrServer单实例
HttpSolrServer线程安全,如果使用下面构造器,必须对所有的请求重用相同的实例.如果实例在运行中创建的,它可能会导致连接泄漏.推荐的做法就是保持每个solr服务url的HttpSolrSer ...
- 创建对象_工厂方法(Factory Method)模式 与 静态工厂方法
工厂方法模式: 定义:为创建对象定义一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟至子类. 应用场景: 客户类不关心使用哪个具体类,只关心该接口所提供的功能: 创建过程比较 ...
- 设计模式系列 1——StaticFactory(静态工厂),AbstractFactory(抽象工厂)
本文出自 代码大湿 代码大湿 本系列持续更新,敬请关注. 1 静态工厂 静态工厂介绍: 静态工厂模式可以实现接口封装隔离的原则.在客户端只知接口而不知实现的时候可以使用静态工厂模式. 源码请点击我 角 ...
随机推荐
- jquery Nestable 获取改变排序后的json数据 拖动排序
<script type="text/javascript"> jQuery(function($){ $('.dd').nestable(); $('.dd-hand ...
- 工具类官网Web原型制作分享-Adobe
Adobe是全球知名的软件开发团队,研发了设计创意领域全球领先的优秀软件产品,为设计行业提供了巨大的价值. 网站原型以图文排版为主,顶部一级导航,弹出面板和面板的使用实现了一级导航下拉的效果. 本原型 ...
- centos7构建python2.7常用开发环境
把下面的代码保存到一个sh文件中执行即可 yum -y install epel-release yum -y install python-pip yum -y install mysql-deve ...
- jsp页面错误的全局处理
网上搜索spring mvc项目全局异常处理: 大致可以找到两种方案 : 方案1: ExceptionHandlerResolver . spring 提供了两种默认实现,当然你也可以自己实现.. 方 ...
- android DatagramSocket send 发送数据出错
安卓4.0以后好像不能在主线程里面使用 socket 所以不管是发送数据还是接收数据需要新开一个了线程: 以下代码是我点击发送是代码: new Thread(new Runnable() { @Ove ...
- maven打包之后为什么class文件中没有注释了?
<!--生成doc jar包--> <plugin> <groupId>org.apache.maven.plugins</groupId> <a ...
- 【转载】为什么任何随便输入的账号使用SYSDBA权限都能登陆oracle
其实简单点就是检查一下你的机器有没有一个ora_dba用户组,而且你登陆os的用户是否在这个组里,有的话问题的原因就找到了,下面是转的高手的介绍 本文环境配置:Oracle10gR2,Windows ...
- [C#.net]WinForm载入窗体完成后自动执行事件
一.以下是网络上可搜索到的次序 当 Windows Form 应用程序启动时,会以下列顺序引发主要表单的启动事件: System.Windows.Forms.Control.Handle ...
- [C#]RichTextBox实现拖放
amespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeC ...
- C语言基础第四次作业
题目7-2,九九乘法表 1.实验代码: #include<stdio.h> int main() { int N, i, j, q; scanf("%d",&N ...