|
|
Posted on 2007-04-25 11:48 沧桑雨迢迢 阅读(6554) 评论(50) 编辑 收藏 网摘
其实,微软的企业库中有一个非常不错的数据操作类了.但是,不少公司(起码我遇到的几个...),对一些"封装"了些什么的东西不太敢用,虽然我推荐过微软的企业库框架了...但是还是要"评估"...一评就是几个月...而且,一些公司有的根本就是裸ado.net开发,或者自己封装的数据库操作类非常别扭,很不好用. 这里我给大家共享一个我参照企业库中的数据操作组件编码风格写的数据库操作类,对使用它的程序员来说,编码是很舒服滴(起码我觉得很好撒).以下是代码,很简单的,没有做任何多余的封装,只是改变了ADO.NET的编码步骤,方便了具体开发数据库操作代码的程序员.
using System;
using System.Data;
using System.Data.Common;
using System.Configuration;

public class DbHelper
 {
private static string dbProviderName = ConfigurationManager.AppSettings["DbHelperProvider"];
private static string dbConnectionString = ConfigurationManager.AppSettings["DbHelperConnectionString"];

private DbConnection connection;
public DbHelper()
 {
this.connection = CreateConnection(DbHelper.dbConnectionString);
}
public DbHelper(string connectionString)
 {
this.connection = CreateConnection(connectionString);
}
public static DbConnection CreateConnection()
 {
DbProviderFactory dbfactory = DbProviderFactories.GetFactory(DbHelper.dbProviderName);
DbConnection dbconn = dbfactory.CreateConnection();
dbconn.ConnectionString = DbHelper.dbConnectionString;
return dbconn;
}
public static DbConnection CreateConnection(string connectionString)
 {
DbProviderFactory dbfactory = DbProviderFactories.GetFactory(DbHelper.dbProviderName);
DbConnection dbconn = dbfactory.CreateConnection();
dbconn.ConnectionString = connectionString;
return dbconn;
}

public DbCommand GetStoredProcCommond(string storedProcedure)
 {
DbCommand dbCommand = connection.CreateCommand();
dbCommand.CommandText = storedProcedure;
dbCommand.CommandType = CommandType.StoredProcedure;
return dbCommand;
}
public DbCommand GetSqlStringCommond(string sqlQuery)
 {
DbCommand dbCommand = connection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.CommandType = CommandType.Text;
return dbCommand;
}

 增加参数#region 增加参数
public void AddParameterCollection(DbCommand cmd, DbParameterCollection dbParameterCollection)
 {
foreach (DbParameter dbParameter in dbParameterCollection)
 {
cmd.Parameters.Add(dbParameter);
}
}
public void AddOutParameter(DbCommand cmd, string parameterName, DbType dbType, int size)
 {
DbParameter dbParameter = cmd.CreateParameter();
dbParameter.DbType = dbType;
dbParameter.ParameterName = parameterName;
dbParameter.Size = size;
dbParameter.Direction = ParameterDirection.Output;
cmd.Parameters.Add(dbParameter);
}
public void AddInParameter(DbCommand cmd, string parameterName, DbType dbType, object value)
 {
DbParameter dbParameter = cmd.CreateParameter();
dbParameter.DbType = dbType;
dbParameter.ParameterName = parameterName;
dbParameter.Value = value;
dbParameter.Direction = ParameterDirection.Input;
cmd.Parameters.Add(dbParameter);
}
public void AddReturnParameter(DbCommand cmd, string parameterName, DbType dbType)
 {
DbParameter dbParameter = cmd.CreateParameter();
dbParameter.DbType = dbType;
dbParameter.ParameterName = parameterName;
dbParameter.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(dbParameter);
}
public DbParameter GetParameter(DbCommand cmd, string parameterName)
 {
return cmd.Parameters[parameterName];
}

#endregion

 执行#region 执行
public DataSet ExecuteDataSet(DbCommand cmd)
 {
DbProviderFactory dbfactory = DbProviderFactories.GetFactory(DbHelper.dbProviderName);
DbDataAdapter dbDataAdapter = dbfactory.CreateDataAdapter();
dbDataAdapter.SelectCommand = cmd;
DataSet ds = new DataSet();
dbDataAdapter.Fill(ds);
return ds;
}

public DataTable ExecuteDataTable(DbCommand cmd)
 {
DbProviderFactory dbfactory = DbProviderFactories.GetFactory(DbHelper.dbProviderName);
DbDataAdapter dbDataAdapter = dbfactory.CreateDataAdapter();
dbDataAdapter.SelectCommand = cmd;
DataTable dataTable = new DataTable();
dbDataAdapter.Fill(dataTable);
return dataTable;
}

public DbDataReader ExecuteReader(DbCommand cmd)
 {
cmd.Connection.Open();
DbDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
}
public int ExecuteNonQuery(DbCommand cmd)
 {
cmd.Connection.Open();
int ret = cmd.ExecuteNonQuery();
cmd.Connection.Close();
return ret;
}

public object ExecuteScalar(DbCommand cmd)
 {
cmd.Connection.Open();
object ret = cmd.ExecuteScalar();
cmd.Connection.Close();
return ret;
}
#endregion

 执行事务#region 执行事务
public DataSet ExecuteDataSet(DbCommand cmd,Trans t)
 {
cmd.Connection = t.DbConnection;
cmd.Transaction = t.DbTrans;
DbProviderFactory dbfactory = DbProviderFactories.GetFactory(DbHelper.dbProviderName);
DbDataAdapter dbDataAdapter = dbfactory.CreateDataAdapter();
dbDataAdapter.SelectCommand = cmd;
DataSet ds = new DataSet();
dbDataAdapter.Fill(ds);
return ds;
}

public DataTable ExecuteDataTable(DbCommand cmd, Trans t)
 {
cmd.Connection = t.DbConnection;
cmd.Transaction = t.DbTrans;
DbProviderFactory dbfactory = DbProviderFactories.GetFactory(DbHelper.dbProviderName);
DbDataAdapter dbDataAdapter = dbfactory.CreateDataAdapter();
dbDataAdapter.SelectCommand = cmd;
DataTable dataTable = new DataTable();
dbDataAdapter.Fill(dataTable);
return dataTable;
}

public DbDataReader ExecuteReader(DbCommand cmd, Trans t)
 {
cmd.Connection.Close();
cmd.Connection = t.DbConnection;
cmd.Transaction = t.DbTrans;
DbDataReader reader = cmd.ExecuteReader();
DataTable dt = new DataTable();
return reader;
}
public int ExecuteNonQuery(DbCommand cmd, Trans t)
 {
cmd.Connection.Close();
cmd.Connection = t.DbConnection;
cmd.Transaction = t.DbTrans;
int ret = cmd.ExecuteNonQuery();
return ret;
}

public object ExecuteScalar(DbCommand cmd, Trans t)
 {
cmd.Connection.Close();
cmd.Connection = t.DbConnection;
cmd.Transaction = t.DbTrans;
object ret = cmd.ExecuteScalar();
return ret;
}
#endregion
}

public class Trans : IDisposable
 {
private DbConnection conn;
private DbTransaction dbTrans;
public DbConnection DbConnection
 {
 get { return this.conn; }
}
public DbTransaction DbTrans
 {
 get { return this.dbTrans; }
}

public Trans()
 {
conn = DbHelper.CreateConnection();
conn.Open();
dbTrans = conn.BeginTransaction();
}
public Trans(string connectionString)
 {
conn = DbHelper.CreateConnection(connectionString);
conn.Open();
dbTrans = conn.BeginTransaction();
}
public void Commit()
 {
dbTrans.Commit();
this.Colse();
}

public void RollBack()
 {
dbTrans.Rollback();
this.Colse();
}

public void Dispose()
 {
this.Colse();
}

public void Colse()
 {
if (conn.State == System.Data.ConnectionState.Open)
 {
conn.Close();
}
}
}
那么如何使用它呢?下面我给出一些基本的使用示例,基本能满足你大部分的数据库操作需要了. 1)直接执行sql语句
DbHelper db = new DbHelper();
DbCommand cmd = db.GetSqlStringCommond("insert t1 (id)values('haha')");
db.ExecuteNonQuery(cmd);
2)执行存储过程
DbHelper db = new DbHelper();
DbCommand cmd = db.GetStoredProcCommond("t1_insert");
db.AddInParameter(cmd, "@id", DbType.String, "heihei");
db.ExecuteNonQuery(cmd);
3)返回DataSet
DbHelper db = new DbHelper();
DbCommand cmd = db.GetSqlStringCommond("select * from t1");
DataSet ds = db.ExecuteDataSet(cmd);
4)返回DataTable
DbHelper db = new DbHelper();
DbCommand cmd = db.GetSqlStringCommond("t1_findall");
DataTable dt = db.ExecuteDataTable(cmd);
5)输入参数/输出参数/返回值的使用(比较重要哦)
DbHelper db = new DbHelper();
DbCommand cmd = db.GetStoredProcCommond("t2_insert");
db.AddInParameter(cmd, "@timeticks", DbType.Int64, DateTime.Now.Ticks);
db.AddOutParameter(cmd, "@outString", DbType.String, 20);
db.AddReturnParameter(cmd, "@returnValue", DbType.Int32);

db.ExecuteNonQuery(cmd);

string s = db.GetParameter(cmd, "@outString").Value as string;//out parameter
int r = Convert.ToInt32(db.GetParameter(cmd, "@returnValue").Value);//return value

6)DataReader使用
DbHelper db = new DbHelper();
DbCommand cmd = db.GetStoredProcCommond("t2_insert");
db.AddInParameter(cmd, "@timeticks", DbType.Int64, DateTime.Now.Ticks);
db.AddOutParameter(cmd, "@outString", DbType.String, 20);
db.AddReturnParameter(cmd, "@returnValue", DbType.Int32);

using (DbDataReader reader = db.ExecuteReader(cmd))
 {
dt.Load(reader);
}
string s = db.GetParameter(cmd, "@outString").Value as string;//out parameter
int r = Convert.ToInt32(db.GetParameter(cmd, "@returnValue").Value);//return value
 7)事务的使用.(项目中需要将基本的数据库操作组合成一个完整的业务流时,代码级的事务是必不可少的哦)
pubic void DoBusiness()
 {
using (Trans t = new Trans())
 {
try
 {
D1(t);
throw new Exception();//如果有异常,会回滚滴
D2(t);
t.Commit();
}
catch
 {
t.RollBack();
}
}
}
public void D1(Trans t)
 {
DbHelper db = new DbHelper();
DbCommand cmd = db.GetStoredProcCommond("t2_insert");
db.AddInParameter(cmd, "@timeticks", DbType.Int64, DateTime.Now.Ticks);
db.AddOutParameter(cmd, "@outString", DbType.String, 20);
db.AddReturnParameter(cmd, "@returnValue", DbType.Int32);

if (t == null) db.ExecuteNonQuery(cmd);
else db.ExecuteNonQuery(cmd,t);

string s = db.GetParameter(cmd, "@outString").Value as string;//out parameter
int r = Convert.ToInt32(db.GetParameter(cmd, "@returnValue").Value);//return value
}
public void D2(Trans t)
 {
DbHelper db = new DbHelper();
DbCommand cmd = db.GetSqlStringCommond("insert t1 (id)values(' ..')");
if (t == null) db.ExecuteNonQuery(cmd);
else db.ExecuteNonQuery(cmd, t);
}以上我们好像没有指定数据库连接字符串,大家如果看下DbHelper的代码,就知道要使用它必须在config中配置两个参数,如下:
<appSettings>
<add key="DbHelperProvider" value="System.Data.SqlClient"/>
<add key="DbHelperConnectionString" value="Data Source=(local);Initial Catalog=DbHelperTest;Persist Security Info=True;User ID=sa;Password=sa"/>
</appSettings>其实,DbHelper需要的仅仅是两个字符串,你可以自己修改,作成加密什么的... 好了,就这样,DbHelper的代码是非常简单和透明的,只是在ado.net上做了一点小包装,改变了一下使用它的程序员的编码方式,去除掉一些比较"物理级"的编程概念,如connection的open和close之类的,使程序员更专注于业务逻辑代码的编写,少死掉点脑细胞,另外,统一了数据操作层的数据操作代码的风格和格式,维护起来很方便的撒~~~ 另:以上代码大家可以随意使用, 不需要给我版权费的啦,嘿嘿.如果大家发现有什么BUG,或者有更好的数据操作类的实现方式,请联系我哦.
Feedback
我很想晕一下...
有些朋友问我要源代码...我全贴在上面了,你只要复制下就可以了撒.
以后 直接打包 提供下载 程序员都是很懒的 复制又不是多了一布。 啊嘎嘎
支持一下,这样的东西不少,关键是性能好,使用方便,移植数据库方便就好
其实ADO.NET 的效率是相当高的 。建议大家用
我倒.
这个dbHelper就是ADO.NET...它只是改变了下编码方式而已.
挺好,可惜只能在.net2.0里使用,.net1.1不支持吧。
@jyk
DbProviderFactories和DbProviderFactory是2.0的东西
其实简单就是很好 ,搞的 复杂的很 大人小孩都不好用。娃哈哈
为什么不敢用呢,源代码都是有的,还怕有什么漏洞吗?
其实这个DbHelper可以支持多数据库切换操作,你只需要在new DbHelper(connectionString)以及Trans t = new Trans(connectionString)时,传递进连接字符串即可;而且由于使用的是DbProviderFactory这样的抽象数据操作类,天然支持多种类数据库操作.
但是我没在文章里写出来,因为我觉得这个DbHelper只做简单的事,它只在简单的系统和项目中得到生存.如果你的项目对数据库操作的要求比较复杂,那么我不推荐你使用这个dbHelper,你应该尝试看下微软的企业库,它才是你需要的.
public void AddReturnParameter(DbCommand cmd, string parameterName, DbType dbType)
{
DbParameter dbParameter = cmd.CreateParameter();
dbParameter.DbType = dbType;
dbParameter.ParameterName = parameterName;
dbParameter.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(dbParameter);
}
写成一个静态的Parameter[],存储在内存中,这样对于经常操作数据库来说非常方便,不必要每次去建立,而且速度方面又有提增。缺点就是占内存。
DAAB已经很好用了萨,干嘛还要自己写呢?没有解决根本问题,还是很麻烦,没有更方便地解决问题
连接对像用static 是不是会有问题,
如果数据操作中出错,怎么办。你下次再使用它。可能错误还停在那。。
正如我前面说的,DbHelper只是一个简单的包装,它不做任何的其他事情...它不优化,它不XXX...它很简单,它也很实用...它是一个很"轻"很小的东西,这是它存在的意义...
@web 我的博客
连接对象没有用static...
连接字符串用static了,因为这里的字符串获取是从config文件中获取的,这是需要一点点开销滴,用static的话,就执行一次...另外,你可以自己修改连接字符串的获取方式...
没必要什么都自己写, 资源浪费了. 不过, 好象自己身边的很多人也都喜欢自己写, 不太明白~
楼主总有一天你会觉得写这个东西是浪费时间,以前写了n次的人飘过。
1)写这个东西很简单,基本上2~3小时就能完成.即时是浪费时间,浪费的时间也很少.
2)这个东西有用,至少在我见过的几个公司中,他们的数据操作类没我写的好.
3)我觉得能给一些人起码有参考的价值,它是有存在的意义和价值的,它的设计目标就是简单,尽量的简单,尽量的小,尽量的透明.(有N多优化的做法,但是它不需要,如果都加上去,它就不是它了,它就是MS 企业库了.)
我贴出这个东西的一个想法,就是想到了起码会有一些人需要和使用它的,而且我也已经吧它应用在好几个实际项目中了.有人需要的东西就不会是浪费时间的东西,即使只是我一个人在使用.
两三年前写过一个几乎一致的东西…… http://www.cnblogs.com/wuvist/archive/2004/10/23/55726.html
偶自己一直用,并且改进到现在……
现在已经演变到支持多数据库,正企图朝ORM发展……写类似: <Table(PrimaryKeyName:="web_customers")> _ Public Class Customer Inherits orm
<Column(Size:=40, ColumnType:=SqlDbType.NVarChar)> _ Public Username As Column.text Public Password As Column.binary <Column(Size:=100, ColumnType:=SqlDbType.NVarChar)> _ Public F_name As Column.text <Column(Size:=100, ColumnType:=SqlDbType.NVarChar)> _ Public G_name As Column.text <Column(Size:=100, ColumnType:=SqlDbType.NVarChar)> _ Public C_name As Column.text <Column(Size:=510, ColumnType:=SqlDbType.NVarChar)> _ Public Email As Column.text <Column(Size:=16, ColumnType:=SqlDbType.NVarChar)> _ Public HP As Column.text Public Booking As Column.int Public Activate As Column.bit
End Class
的代码,便可以直接: dim c as Customer c = Customer.FindById(2) c.Email.value = "XXX' c.Save()
c = New Customer c.Username.value = "YYY" c.Addnew()
支持foreign key,比方说: Public Class Company Inherits orm
<Column(Size:=40, ColumnType:=SqlDbType.NVarChar)> _ Public name As Column.text
end Class
Public Class Customer Inherits orm
Public company As Company
End Class
dim c as Customer = Customer.FindbyId(1) response.write(c.company.name.value)
其中 company.name是lazyload的,程序用到的时候,才自动去数据库获取。
楼主的文章,使得偶更加有信心把偶的dbhelper(偶不想称其为ORM)发布出来……
今天仔细来看了看源代码
才发现
每个方法都没考虑线程安全性
对新手来说
用起来
确实很危险
如果自己用也就罢了
如果拿出来共享给别人用的
最好考虑周全
BZ说是自己公司都在用的东西
那么就很替你公司担心了
如果你辞职了
来了新员工接手
都不知道这些方法都是没有线程安全的
那就很危险的了
如果只是讨论技术
为了清晰逻辑省去一些辅助结构是可以的
但是用作工业用途就8行啦
这一点...我上面说了很清楚了...
你不能怪我没做数据缓存,没做XXX性能优化,没做YYY处理...
这只是一个最简单的ADO.NET的封装,一点:它比你写裸ADO.NET要好...很多公司,开发东西时,就是用裸ADO.NET开发的,我看也没考虑什么XXX,YYY,ZZZ...
@亚历山大同志
感谢你的评论,至少看了我写的代码,我还是很感谢滴,我对ADO.NET也没什么深入的研究,有什么遗漏的地方请包涵啦
偶一直都直接使用Microsoft.Practices.EnterpriseLibrary.Data 源码公开的,有什么好怕的
嗯?上面一条我没有回复啊,我是写在我的博客里的,怎么也跑到这里来了?
good--引用--------------------------------------------------
--------------------------------------------------------
不明白为什么不Close数据库也能close ???
public DbDataReader ExecuteReader(DbCommand cmd, Trans t)
{
cmd.Connection.Close();
cmd.Connection = t.DbConnection;
cmd.Transaction = t.DbTrans;
DbDataReader reader = cmd.ExecuteReader();
//DataTable dt = new DataTable();
return reader;
}
//DataTable dt = new DataTable()
好象没用吧?
说几个设计上的: 1 命名过长,如果能够缩短一些比较好.
2 命名中如果能够不用"SQL"这三个字比较好,因为如果用到ACCESS,SQLITE,MYSQL的话, "SQL"这三个字会有可能引起潜在的误会
3 我是大概看了一遍,没有细看,但是感觉Command对象可以没有必要取出来的.例如创建Dataset的那段,如果能够像下面这样可能会更好: DataSet ds = db.ExecuteDataSet("SQL语句");
4 在“获取数据”这个概念上,又添加进一层“事务”的概念或许会不妥,还可以更简洁些,如果是一条SQL语句,用不用事务无所谓,如果是多条SQL,就在类的内部自动使用事务,或者通过一个BOOL参数来开启事务就行了。
5 DataSet和DataTable完全可以共用一个函数来获取。不必专门区分一个获取SET,一个获取TABLE
再加一条: ConfigurationManager.AppSettings["DbHelperProvider"] 是什么?什么也不是。
如果其它的程序也需要用这个参数怎么办? 如果能够直接在构造函数中增加一个参数,传递“SYSTEM.DATA.SQLCLIENT”或者“SYSTEM.DATA.OLEDB”这些字符串,那么就不需要依赖外部XML配置了,也就直接能够既使用在ASP.NET,又实用在EXE,何乐而不为呢?
这个HELP类支持事务和SQL语句操作,不支持存储过程的把
有个疑问。你上面执行块里的那些数据中的连接对象是怎么关闭,看你例子中也没有涉及到,只看到你的事务中有关闭方式。。。
这样是否会存在问题?望指教?
|