周末了比较悠闲,把本身的orm框架整理了下,开源了.sql
已经作出来的东西一般感受有些简单,一些新手或许听到"框架"一类的词以为有些"高深",简单来讲orm就是把ado的封装.数据库
在介绍这个框架的第一篇博文,已经把DalBase介绍了一下设计思路,本篇的DBHelper对象也是给dalBase来用的,能够说框架的全部定义对象都是为了它.c#
这里起名叫DBHelper,由于我也是从写SQLHelper开始的,DBHelper只不过是全部类型对ado操做的各类方法的封装,因此本篇博文但愿给c#新手,或是对ado.net认识比较模糊的有一些帮助.框架
首先DBHelper定义是个抽象的,由于我不知道DalBase 到底要访问哪一种数据库,但我知道无论哪中数据库都会有连接字符串,那我就要求,必需要有链接字符串.ide
public DbHelperBase(string connStr) { _ConnStr = connStr; }
DbHelper是个抽象的,那它的成员必然就不能有具体对象.spa
那就把ado.net经常使用的对象定义出来.(若是你是初学者,个人建议是 用到哪一个对象再去定义,不然到后期本身都不知道定义它干啥呢).net
protected abstract DbConnection DBConnectionObj { get; } protected abstract DbCommand DbCommandObj { get; } protected abstract DbDataAdapter DbDataAdapterObj { get; } protected DbTransaction DbTransObj; public DbConnection CurrentConnection { get { return DBConnectionObj; } }
说明一下,为何事务对象不是抽象的,由于事务对象始终是有DbConnection来建立的,我不用知道它具体是什么类型.设计
DbConnection 对象public也是为了扩展其它功能而存在的.code
定义了是否事务的变量,全部ado操做都会判断当前是否处于事务的标记.orm
bool _IsTrans = false;
初学.net的朋友,应该都会有一个SQLHelper的类,我也曾经看过都大同小异,并且广泛都没有事务的实现,若是你中枪了,那么恭喜你,你即将会改变你sqlHelper的实现.
以下代码:
/// <summary> /// 执行一条指定命令类型(SQL语句或存储过程等)的SQL语句,返回所影响行数 /// </summary> public int ExecNonQuery(string sqlText, CommandType cmdType, params DbParameter[] param) { using (SqlConnection conn = new SqlConnection(_ConnStr)) { using (SqlCommand cmd = new SqlCommand(sqlText, conn)) { cmd.CommandType = cmdType; if (param != null) cmd.Parameters.AddRange(param); conn.Open(); return cmd.ExecuteNonQuery(); } } }
以上代码看起来是没什么问题,但若是要启用事务的话想一想是否能够实现呢?
若是说改造一下加上事务的代码就行的话
以下:
SqlTransaction tran = conn.BeginTransaction();
cmd.Transaction = tran;
这样显然是错的,由于咱们每每多条执行语句一般是分屡次调用 ExecNonQuery() 方法的.
这样的一个ado方法的封装显然是不合理的.
若是多个增删改查(注意:查询也可能在是事务里)的方法,在一个事务里,那么必须是一个数据库链接(Connection)
这就是为何把那三个对象定义到外面的缘由之一了,最重要的缘由是我须要子类去重写它.
下面看看个人实现:
/// <summary> /// 打开链接,若是已经打开则什么都不执行了 /// </summary> void OpenConnection() { if (DBConnectionObj.State != ConnectionState.Open) { DBConnectionObj.ConnectionString = _ConnStr; DBConnectionObj.Open(); } }
/// <summary> /// 给当前DbCommand对象赋值,而且OpenConnection(); /// </summary> void SetCommandAndOpenConnect(string sqlText, CommandType cmdType, params DbParameter[] param) { //按说赋值Connection,CommandType,是不用屡次赋值的 DbCommandObj.CommandType = cmdType; DbCommandObj.Connection = DBConnectionObj; DbCommandObj.Parameters.Clear(); if (param != null) { DbCommandObj.Parameters.AddRange(param); } DbCommandObj.CommandText = sqlText; OpenConnection(); }
/// <summary> /// 执行一条指定命令类型(SQL语句或存储过程等)的SQL语句,返回所影响行数 /// </summary> public int ExecNonQuery(string sqlText, CommandType cmdType, params DbParameter[] param) { try { SetCommandAndOpenConnect(sqlText, cmdType, param); return DbCommandObj.ExecuteNonQuery(); } catch (Exception ex) { throw ex; } finally { CloseConnect(); } }
看到这三个方法或许对于初学者会感到迷茫了,没有看到任何有关事务的代码呢,兜个圈子,如今想象一下若是加事务的话,须要作什么?
咱们先从理论上认识一下,事务处理的流程
1.指定事务是哪一个Connection
2.Command的事务对象指定到该事务.
3.Open()
4.提交或回滚(我是能写汉字的地方毫不写拼音)
5.关闭链接.
继续说这几个方法,为何定义SetCommandAndOpenConnect 和 OpenConnection 这两个方法,本着尽可能减小重复代码的原则.仅此而已.
既然Connection和Command都已经定义到方法外了,那就是说我只要再执行Command.ExecuteNonQuery()方法前,给他们赋值就好了.
也就是开始事务只须要给这个两个对象赋值便可
事务的相关代码以下:
/// <summary> /// 开始执行事务 /// </summary> public void TransStart() { OpenConnection(); DbTransObj = DBConnectionObj.BeginTransaction(); DbCommandObj.Transaction = DbTransObj; _IsTrans = true; } /// <summary> /// 事务提交 /// </summary> public void TransCommit() { _IsTrans = false; DbTransObj.Commit(); CloseConnect(); } /// <summary> /// 事务回滚 /// </summary> public void TransRollback() { _IsTrans = false; DbTransObj.Rollback(); CloseConnect(); }
这就是事务的方法了.
最后一个CloseConnect()方法,差点把它遗忘了
/// <summary> /// 关闭链接,若是没有开始事务或链接打开时才关闭 /// </summary> void CloseConnect() { if (!_IsTrans) { if (DBConnectionObj.State == ConnectionState.Open) { DBConnectionObj.Close(); DBConnectionObj.Dispose(); } } }
当开始事务时,链接是不能关的.只有提交了或回滚了才会把当前链接断掉.
到这里其实DbHelper的设计基本完成,再贴一下关于查询的几个方法,和执行相似就不解释了.
/// <summary> /// 得到首行首列 /// </summary> public object GetScalar(string sqlText, CommandType cmdType, params DbParameter[] param) { try { SetCommandAndOpenConnect(sqlText, cmdType, param); return DbCommandObj.ExecuteScalar(); } catch (Exception ex) { throw ex; } finally { CloseConnect(); } } /// <summary> /// 执行一条SQL语句返回DataSet对象 /// </summary> public DataSet GetDataSet(string sqlText, CommandType cmdType, params DbParameter[] param) { try { SetCommandAndOpenConnect(sqlText, cmdType, param); DbDataAdapterObj.SelectCommand = DbCommandObj; DataSet ds = new DataSet(); DbDataAdapterObj.Fill(ds); return ds; } catch (Exception ex) { throw ex; } finally { CloseConnect(); } } /// <summary> /// 得到DataReader对象 /// </summary> public DbDataReader GetDataReader(string sqlText, CommandType cmdType, params DbParameter[] param) { try { SetCommandAndOpenConnect(sqlText, cmdType, param); CommandBehavior cmdBehavior = CommandBehavior.CloseConnection; if (_IsTrans) { cmdBehavior = CommandBehavior.Default; } DbDataReader dbReader = DbCommandObj.ExecuteReader(cmdBehavior); return dbReader; } catch (Exception ex) { throw ex; } finally { //DataReader用dbReader对象来关闭 //CloseConnect(); } }
这里须要注意的是关于返回DataReader对象时不能关闭Connect,和 cmdBehavior 的赋值.
好了,到这DBHelper的设计和核心代码已经所有实现了.
试想一下我如今要完成SQLServerHelper的实现须要作的是什么?
固然只要实现父类的那几个抽象属性就好了.
代码以下:
public class SQLHelper : DbHelperBase { public SQLHelper(string connStr) : base(connStr) { } SqlConnection _DBConnectionObj; SqlCommand _DbCommandObj; SqlDataAdapter _DbDataAdapterObj; protected override DbConnection DBConnectionObj { get { //SqlBulkCopy aa = new SqlBulkCopy(new SqlConnection()); if (_DBConnectionObj == null) { _DBConnectionObj = new SqlConnection(_ConnStr); } return _DBConnectionObj; } } protected override DbCommand DbCommandObj { get { if (_DbCommandObj == null) { _DbCommandObj = new SqlCommand(); } return _DbCommandObj; } } protected override DbDataAdapter DbDataAdapterObj { get { if (_DbDataAdapterObj == null) { _DbDataAdapterObj = new SqlDataAdapter(); } return _DbDataAdapterObj; } } }
OracleHelper,oledbhelper,SQLiteHelper,就不贴代码了.
转载建议标明出处(我历来不强迫别人作我管不了的事).
整个框架的源码在介绍框架的第一篇博文里有.
欢迎吐槽,点赞,建议,批评,指正,抄袭.