用设计模式开发通用数据库访问 ADO.NET

2019-03-02 23:43|来源: 网路

用设计模式开发通用数据库访问器

      我们都希望在开发软件的时候能少写一些代码,希望能到处使用,希望不用管什么样的数据库软件都能用,我们该怎么办呢?

我们操作数据库时用到些什么类

       一般来说,我们对数据库进行操作时都会用到一些类,下面我就对着些类做个总结:
1.  SQLServer:
a)         System.Data.SqlClient.SqlDataAdapter:SQL数据适配器。表示用于填充 DataSet 和更新 SQL Server 数据库的一组数据命令和一个数据库连接。无法继承此类。该类继承于System.Data.Common.DbDataAdapter和实现接口System.Data.IDbDataAdapter。采用Adapter模式设计。
b)        System.Data.SqlClient.SqlConnection:SQL数据库连接。表示 SQL Server 数据库的一个打开的连接。无法继承此类。
c)        System.Data.SqlClient.SqlCommandBuilder:SQL数据库命令生成器。自动生成具有以下用途的单表命令:使对 DataSet 所做的更改与关联的 SQL Server 数据库相协调。无法继承此类。采用Builder模式设计。
另外还有一些,但是在本文中将用不到,所以这里也就不再叙述了。
2.  Oracle:
a)         System.Data.OracleClient.OracleDataAdapter:Oracle数据适配器。表示用于填充 DataSet 和更新Oracle数据库的一组数据命令和到数据库的连接。无法继承此类。该类继承于System.Data.Common.DbDataAdapter和实现接口System.Data.IDbDataAdapter。采用Adapter模式设计。
b)        System.Data.OracleClient.OracleConnection:Oracle数据库连接。表示一个到Oracle数据库的打开的连接。无法继承此类。
c)        System.Data.OracleClient.OracleCommandBuilder:Oracle数据库命令生成器。自动生成用于协调 DataSet 的更改与关联的Oracle数据库的单表命令。无法继承此类。采用Builder模式设计。
3.  Odbc:
a)         System.Data.Odbc.OdbcDataAdapter:Odbc类型数据数据适配器。表示数据命令集和到Odbc数据源的连接,它们用于填充 DataSet 以及更新该数据源。无法继承此类。。该类继承于System.Data.Common.DbDataAdapter和实现接口System.Data.IDbDataAdapter。采用Adapter模式设计。
b)        System.Data.Odbc.OdbcConnection:Odbc数据库连接。表示到Odbc数据源的连接是打开的。
c)        System.Data.Odbc.OdbcCommandBuilder:Odbc数据库命令生成器。自动生成用于协调 DataSet 的更改与关联的Odbc类型数据源的单表命令。无法继承此类。采用Builder模式设计。
4.  OleDb:
a)         System.Data.OleDb.OleDbDataAdapter:Odbc类型数据数据适配器。表示数据命令集和到OleDb数据源的连接,它们用于填充 DataSet 以及更新该数据源。无法继承此类。。该类继承于System.Data.Common.DbDataAdapter和实现接口System.Data.IDbDataAdapter。采用Adapter模式设计。
b)        System.Data.OleDb.OleDbConnection:OleDb数据库连接。表示到OleDb数据源的连接是打开的。
c)        System.Data.OleDb.OleDbCommandBuilder:OleDb数据库命令生成器。自动生成用于协调 DataSet 的更改与关联的OleDb类型数据源的单表命令。无法继承此类。采用Builder模式设计。

我们需要什么样的数据操作器

       当然是越简单越好了,功能倒不一定要强大,够用就行。希望能支持多种数据库,使用这个操作器的程序不用再考虑是那种数据库;希望能对多个数据库操作,一个项目使用多个数据库却不对增加编程复杂度;希望支持事务,失败能够自动回滚。功能嘛,能读取数据、更新数据就可以了。

通用数据操作器的思路

       对数据库的操作其实就是两件事:出和进。出呢就是从数据库中读取数据,进就是将数据写回数据库,包括新增数据、更新数据、删除数据。
       那么对这两个件事情该怎么做呢?
读取数据时,我们是打开一个连接,实例化一个数据适配器然后填充数据集,关闭连接,即可。这里要注意的是,由于数据集里的表经常是数据库里多个数据表join的结果,所以你甭想让操作器自动生成查询语句,得你自己写。
写入数据的时候,就会有一些麻烦,但因为都是执行单表操作所以你可以不用自己写SQL语句,让操作器自己生成好了。
那么一步步怎么做呢?先打开一个数据库连接,再生成一个查询字符串,接着这两个东东实例化一个数据适配器,在生成一个CommandBuilder的实例并注册为DataAdapter的侦听器,接着配置事务。然后更新数据库,最后关闭连接。事务不能更早配置,是因为配置的事务之后便不允许数据适配器的命令为空。
思路有了,后面就很简单了,我们只需要为每一种数据库连接定义这些操作,然后根据实际情况调用就可以了。
当然我们不希望使用哪种数据库的由调用它的系统作为参数传入,定义在配置文件中似乎更好一些。
由于可能有多个数据库,所以我们应当体现这种情况。比如我们可以定义默认数据库连接为“DBCon”,数据库A的连接为“ADBCon”。
由于要实现多张表的操作,所以我们要定义一个数据集表和表名的映射。

代码实现

       首先定义一个枚举,以指定可以支持哪些数据库:
/// <summary>
     /// 数据库类型枚举
     /// </summary>
     public enum DBType
     {
         /// <summary>
         /// SQLServer
         /// </summary>
         SQLServer,
         /// <summary>
         /// Oracle
         /// </summary>
         Oracle,
         /// <summary>
         /// OleDB
         /// </summary>
         OleDb,
         /// <summary>
         /// Odbc
         /// </summary>
         Odbc
     }
 
     定义一个类来扩展DataTable:
     /// <summary>
     /// 用于更新数据库的数据表、库表名对
     /// </summary>
     public class DataTableExtend
     {
         /// <summary>
         /// 数据表
         /// </summary>
         public System.Data.DataTable dataTable;
 
         /// <summary>
         /// 数据表映射到数据库的表名
         /// </summary>
         public string dataTableName;
 
         /// <summary>
         /// 用于更新数据库的数据表、库表名对构造函数
         /// </summary>
         /// <param name="myTable">用于更新数据库的数据表</param>
         /// <param name="myTableName">数据表映射到数据库的表名</param>
         public DataTableExtend(System.Data.DataTable myTable, string myTableName)
         {
              dataTable = myTable;
              dataTableName = myTableName;
         }
     }
 
     然后写一个类来读取配置文件并获取数据库连接字符串:
     /// <summary>
     /// DBSetting 的摘要说明。
     /// </summary>
     public class DBSetting
     {
         /// <summary>
         /// 数据库连接字符串后缀
         /// </summary>
         public static string DBConnectionEnds
         {
              get
              {
                   return "DBCon";
              }
         }
 
         /// <summary>
         /// 数据库类型后缀
         /// </summary>
         public static string DBTypeEnds
         {
              get
              {
                   return "DBType";
              }
         }
/// <summary>
         /// 获取指定数据库的类型
         /// </summary>
         /// <param name="dbName">指定的数据库名</param>
         /// <returns>指定数据库的类型</returns>
         public static DBType GetDBType(string dbName)
         {
              string dbType = null;
              dbType = AppConfig.GetAppSetting(dbName + DBTypeEnds);
              if (dbType.ToLower() == DBType.Oracle.ToString().ToLower())
              {
                   return DBType.Oracle;
              }
              if (dbType.ToLower() == DBType.Odbc.ToString().ToLower())
              {
                   return DBType.Odbc;
              }
              if (dbType.ToLower() == DBType.OleDb.ToString().ToLower())
              {
                   return DBType.OleDb;
              }
              else
              {
                   return DBType.SQLServer;
              }
         }
/// <summary>
         /// 保存指定数据库的类型
         /// </summary>
         /// <param name="dbType">指定数据库的类型</param>
         /// <param name="dbName">指定的数据库名</param>
         public static void SaveDBType(DBType dbType,string dbName)
         {
              AppConfig.SaveAppSetting(dbName + DBTypeEnds,dbType.ToString());
         }
/// <summary>
         /// 获取指定数据库的连接字符串
         /// </summary>
         /// <param name="dbName">指定的数据库名</param>
         /// <returns>指定数据库的连接字符串</returns>
         public static string GetDBConnectionString(string dbName)
         {
              return AppConfig.GetAppSetting(dbName + DBConnectionEnds);
         }
 
         /// <summary>
         /// 保存指定数据库的连接字符串
         /// </summary>
         /// <param name="connectionString">连接字符串</param>
         /// <param name="dbName">指定的数据库名</param>
         public static void SaveDBConnectionString(string connectionString, string dbName)
         {
              AppConfig.SaveAppSetting(dbName + DBConnectionEnds,connectionString);
         }
}
 
接着为每一种数据库写一个类来执行针对该数据库的操作,例如针对SQL Server:
/// <summary>
     /// 用于SQL数据源操作的类
     /// </summary>
     public class SQLExec
     {
         /// <summary>
         /// 获取数据库连接,读取由Storm.AppSetting的配置文件中dbName + "DBCon"的设置(如针对数据库Test的配置键是“TestDBCon”),若没有,则抛出异常
         /// </summary>
         /// <param name="dbName">要获取数据连接的数据库名</param>
         /// <returns>得到的数据库连接</returns>
         public static SqlConnection GetDBConnection(string dbName)
         {
              return new SqlConnection(DBSetting.GetDBConnectionString());
         }
 
private void ModifyDataBase(DataTableExtend[] dts, string dbName)
         {
              //打开连接
              SqlConnection sqlCon = GetDBConnection(dbName);
              sqlCon.Open();
              //根据数据表的多少生成多个数据适配器并分别生成SQL语句
              int length = dts.Length;
              SqlDataAdapter[] myDataAdapters = new SqlDataAdapter[length];
              for (int i = 0; i < length; i++)
              {
                   string selectText = GetSelectCommand(dts[i].dataTableName);
                   myDataAdapters[i] = new SqlDataAdapter(selectText, sqlCon);
                   SqlCommandBuilder cb = new SqlCommandBuilder(myDataAdapters[i]);
                   myDataAdapters[i].InsertCommand = cb.GetInsertCommand();
                   myDataAdapters[i].UpdateCommand = cb.GetUpdateCommand();
                   myDataAdapters[i].DeleteCommand = cb.GetDeleteCommand();
              }
              //配置事务
              SqlTransaction myTrans;
              myTrans = sqlCon.BeginTransaction(IsolationLevel.RepeatableRead);
              try
              {
                   for (int i = 0; i < length; i++)
                   {
                       myDataAdapters[i].SelectCommand.Transaction = myTrans;
                       myDataAdapters[i].InsertCommand.Transaction = myTrans;
                       myDataAdapters[i].UpdateCommand.Transaction = myTrans;
                       myDataAdapters[i].DeleteCommand.Transaction = myTrans;
                       //更新数据库
                       myDataAdapters[i].Update(dts[i].dataTable);
                   }
                   myTrans.Commit();
                   sqlCon.Close();
                   for(int i = 0; i < length ; i++)
                   {
                       dts[i].dataTable.AcceptChanges();
                   }
              }
              //如果失败,则自动回滚
              catch(Exception ee)
              {
                   myTrans.Rollback();
                   sqlCon.Close();
                   for(int i = 0; i < length ; i++)
                   {
                       dts[i].dataTable.RejectChanges();
                   }
                   throw ee;
              }
         }
    
/// <summary>
         /// 从数据库中读取数据
         /// </summary>
         /// <param name="dt">要承载数据的数据表</param>
         /// <param name="selectString">查询语句</param>
         public void GetData(DataTable dt, string selectString, string dbName)
         {
SqlDataAdapter myDataAdapter = new SqlDataAdapter(selectString,SQLConfig.GetDBConnection(dbName));
              myDataAdapter.Fill(dt);
         }
        
         //自动生成查询语句
private static string GetSelectCommand(string dataTableName)
         {
              string strGet = "SELECT * FROM " +dataTableName;
              return strGet;
         }
}
 
然后就是写一个类来根据实际情况调用这些东东了:
public class DatabaseExecute
     {
         private string dbName;
         /// <summary>
         /// 目标数据库
         /// </summary>
         public string DBName
         {
              get{ return dbName; }
              set{ dbName = value; }
         }
    
         /// <summary>
         /// 生成DatabaseExecute的实例
         /// </summary>
         public DatabaseExecute()
         {
              dbName = null;
         }
 
         /// <summary>
         /// 用指定的目标数据库生成DatabaseModifier的实例
         /// </summary>
         /// <param name="dbName"></param>
         public DatabaseExecute(string dbName)
         {
              this.dbName = dbName;
         }
         /// <summary>
         /// 从数据库中读取数据
         /// </summary>
         /// <param name="dt">要承载数据的数据表</param>
         /// <param name="selectString">查询语句</param>
         public void GetData(DataTable dt, string selectString)
         {
              //操作指定数据库
              if (DBName != null)
              {
                   if (DBSetting.GetDBType(dbName) == DBType.SQLServer)
                   {
                       SQLExec mySQLExec = new SQLExec();
                       mySQLExec. GetData(dt, selectString, DBName);
                   }
                   else if (DBSetting.GetDBType(dbName) == DBType.Odbc)
                   {
                       OdbcExec myOdbcExec = new OdbcExec();
                       myOdbcExec. GetData(dt, selectString, DBName);
                   }
                   else if (DBSetting.GetDBType(dbName) == DBType.OleDb)
                   {
                       OleDbExec myOleDbExec = new OleDbExec();
                       mySQLExec. GetData(dt, selectString, DBName);
                   }
                   else
                   {
                       OracleExec myOracleExec = new OracleExec();
                       myOracleExec. GetData(dt, selectString, DBName);
                   }
              }
              //操作默认数据库
              else
              {
                   if (DBSetting.GetDBType(“”) == DBType.SQLServer)
                   {
                       SQLExec mySQLExec = new SQLExec();
                       mySQLExec. GetData(dt, selectString, “”);
                   }
                   else if (DBSetting.GetDBType(“”) == DBType.Odbc)
                   {
                       OdbcExec myOdbcExec = new OdbcExec();
                       myOdbcExec. GetData(dt, selectString, “”);
                   }
                   else if (DBSetting.GetDBType(dbName) == DBType.OleDb)
                   {
                       OleDbExec myOleDbExec = new OleDbExec();
                       mySQLExec. GetData(dt, selectString, “”);
                   }
                   else
                   {
                       OracleExec myOracleExec = new OracleExec();
                       myOracleExec. GetData(dt, selectString, “”);
                   }
              }
         }
 
         /// <summary>
         /// 根据数据表组更新数据库
         /// </summary>
         /// <param name="dts">要更新的数据表组</param>
         public void ModifyDataBase(DataTableExtend[] dts)
         {
              //操作指定数据库
              if (dbName != null)
              {
                   if (DBSetting.GetDBType(dbName) == DBType.SQLServer)
                   {
                       SQLExec mySQLExec = new SQLExec();
                       mySQLExec ModifyDataBase(dts,dbName);
                   }
                   else if (DBSetting.GetDBType(dbName) ==  DBType.Odbc)
                   {
                       OdbcExec mySQLExec = new OdbcExec();
                       myOdbcExec ModifyDataBase(dts,dbName);
                   }
                   else if (DBSetting.GetDBType(dbName) == DBType.OleDb)
                   {
                       OleDbExec mySQLExec = new OleDbExec();
                       myOleDbExec ModifyDataBase(dts,dbName);
                   }
                   else
                   {
                       OracleExec mySQLExec = new OracleExec();
                       myOracleExec ModifyDataBase(dts,dbName);
                   }
              }
              //操作默认数据库
              else
              {
                   if (DBSetting.GetDBType(“”) == DBType.SQLServer)
                   {
                        SQLExec mySQLExec = new SQLExec();
                       mySQLExec ModifyDataBase(dts, “”);
                   }
                   else if (DBSetting.GetDBType(dbName) ==  DBType.Odbc)
                   {
                       OdbcExec mySQLExec = new OdbcExec();
                       myOdbcExec ModifyDataBase(dts, “”);
                   }
                   else if (DBSetting.GetDBType(dbName) == DBType.OleDb)
                   {
                       OleDbExec mySQLExec = new OleDbExec();
                       myOleDbExec ModifyDataBase(dts, “”);
                   }
                   else
                   {
                       OracleExec mySQLExec = new OracleExec();
                       myOracleExec ModifyDataBase(dts, “”);
                   }
              }
}
 
这样,在项目中只要引用这个DatabaseExecute类就可以了。
最后,要注意的几点:
1.              对于多表操作而言,因为表间有关联,所以操作的顺序很重要,本构件操作的顺序是从数据表数组的前向后处理,请千万注意表处理的顺序!
2.              默认数据库连接由配置文件中“DBCon”的设置决定,非默认数据库连接由配置文件中“*DBCon”的设置决定,其中星号代表数据库标识
3.              默认数据库类型由配置文件中“DBCon”的设置决定,非默认数据库类型由配置文件中“*DBCon”的设置决定,其中星号代表数据库标识
4.              针对每一个数据库都有两个配置,分别是数据库连接和数据库类型。

转自:http://www.cnblogs.com/rjxiaozhou/archive/2010/07/01/1769318

相关问答

更多
  • 你需要的是某种ORM ,而ADO不是ORM。 所以不行。 您必须编写SQL。 但是,您可以通过编写存储过程来简化操作。 然后您可以使用ADO参数 如果需要,可以将更改保存为内存中的对象,直到需要实际保留它们为止。 然后你可以有一个映射器,它将获取对象并为你编写SQL。 但是,您正在重做已经在ORM中完成的一些工作 What you need is some sort of ORM, and ADO is not an ORM. So, no. You must write the SQL. You coul ...
  • 松散的,轻松的说话 ADO.NET是一个允许您的应用程序与数据库进行通信的命令和对象库。 如果您在VB6 / C ++中使用了ADODB,那么ADO.NET就是.net(vb.net/C#)等价物。 ADO.NET为您提供诸如连接对象,数据集和数据读取器对象等对象。 ADO.NET提供者想象一个像图形或设备驱动程序那样的提供者。 每次将不同的图形卡放入计算机时,都需要有一个新的图形驱动程序才能使显卡充分发挥作用。 ADO.NET也是如此,对于连接到的每种不同类型的数据库(例如Microsoft Access ...
  • 可能存在误解,EF和ADO.NET实际上是在一起工作。 查看概述MSDN 还有一篇帖子显示了从EF4开始使用存储过程:EF4中存储过程的一大步 There might be a misunderstanding, the EF and ADO.NET are actually working together. Look at the overview MSDN Also a post that shows usage of stored procedure starting from EF4: A big ...
  • 简短的回答: 这取决于你执行什么样的操作。 如果你编写好的SQL,你可能会得到性能改进,但是在某些情况下,由于你失去了NHibernate的缓存等,你可能会变得更糟糕。 长答案: 正如你所提到的,NHibernate位于ADO.NET之上,并提供了一个抽象层。 这使得你的生活在许多方面更容易,但是作为所有抽象层,它都有一定的性能成本。 您可能会看到性能优势的主要情况是,您一次操作多个对象,例如更新许多实体或获取大量实体。 这是因为NHibernate会话会跟踪哪些对象被修改等。我的经验是,NHibernat ...
  • 看看http://community.jboss.org/wiki/DatabasesSupportedByNHibernate 。 它显示了用于连接到不同数据库的工具/驱动程序。 例如: Oracle 9i和10g均支持使用Microsoft驱动程序(System.Data.OracleClient)和Oracle驱动程序(Oracle.Data.OracleClient)。 要么: 要使用Firebird,请安装最新的Firebird .NET数据提供程序。 我不确定它是否使用ADO.Net进行SQL ...
  • 一方面,如果它没有损坏,不要修复它。 但另一方面 - VB6? 真? 听起来像ADO与ADO.NET在这里是小土豆... 我认为这个问题更多的是VB和VB.NET,然后整个代码库,技能集以及其他非技术性的考虑在这里发挥作用。 On the one hand, if it ain't broke, don't fix it. But on the other - VB6? Really? Sounds like ADO vs. ADO.NET is small potatoes here... I think ...
  • 当然ADO.NET支持连接! 请参阅ADO.NET:使用OLE DB快速入门教程检索数据 。 Of course ADO.NET supports joins! See ADO.NET: Retrieve Data using OLE DB quickstart tutorial.
  • 绑定控件使用ADO.NET; 他们不是竞争工具,而是互补工具。 一个使用对方,或者使用对象关系映射器,在场景下可以使用ADO.NET。 那有意义吗? 有关这两者的更多信息,asp.net网站有一个有很多优秀资源的学习部分。 Bound controls use ADO.NET; they are not competing tools but complementary tools. One uses each other, or you use an Object Relational Mapper, w ...
  • 默认情况下,ADO.net使用乐观锁定并发,但您还必须查看SQL服务器上发生的情况。 除非您指定NoLock等提示,否则将发出共享锁。 这是一个轻量级锁,允许其他事务读取资源但不允许其他事务修改数据。 读取完数据后释放此锁定 ADO.net uses an optimistic locking concurrency by default but you also have to look at what is happening on the SQL server. Unless you specify ...
  • 使用EF db.Add(); 或者db.SaveChanges或任何其他集成的EF方法,ORM(对象关系映射器),在本例中为EF,将使用ADO.NET(因此EF将使用ADO.NET打开数据库连接,EF将使用“SQL查询”创建ADO.NET,...)。 当然,您可以使用ADO.NET方法自己完成所有这些操作,这些方法有时可以提高查询的性能,但通常需要更多的代码编写。 但一般来说,当你使用EF时,你也使用ADO.NET,只有它在EF方法中实现。 When you use EF db.Add(); or db.S ...