知识点
相关文章
更多最近更新
更多用设计模式开发通用数据库访问器
2019-03-02 23:39|来源: 网路
用设计模式开发通用数据库访问器 |
我们都希望在开发软件的时候能少写一些代码,希望能到处使用,希望不用管什么样的数据库软件都能用,我们该怎么办呢? 我们操作数据库时用到些什么类
一般来说,我们对数据库进行操作时都会用到一些类,下面我就对着些类做个总结:
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/zhuor/archive/2005/11/23/282794
相关问答
更多-
MySQL数据库管理程序的设计与实现[2022-05-02]
建议你下载 phpmyadmin 看看,这是php写的mysql数据库管理工具,可做到对mysql的增删查改、增删用户、授权等…… 总之这个phpmyadmin非常好用,你如果需要自己开发,那么可以参考这个phpmyadmin,看看它的代码。 -
怎样开发数据库?[2024-01-08]
常用的数据库有:access数据库,MS SQL数据库,MY SQL数据库.Oracle数据库.还有DB2,sysbase等数据库。access数据库安装微软office里面自带了access,MS SQL数据库现在主要是用Microsoft SQL 2000 和 2005(2008是刚出来不久的新产品,现在用的还不是很广),Oracle数据库主要是用Oracle database 8i,9i, 10g, 11g。数据库的开发是一门很深奥的学问,现在数据库开发流行遵循三大范式,相关的资料自己可以多去了解。学 ... -
C/S模式数据库前端该用什么语言/平台开发,更适合我的情况.[2023-06-07]
ACCESS没有问题的, 只要你的数据规模不大,完全可以使用ACCESS -
关系数据库设计模式?(Relational Database Design Patterns?)[2022-10-05]
Martin Fowler的“签名系列”( Reatureoring Databases)中有一本书。 这提供了重构数据库的技术列表。 我不能说我已经听到了很多数据库模式的列表。 我还强烈建议David C. Hay的数据模型模式和后续的元数据映射 ,建立在第一个,更有野心和有趣的元数据映射 。 前言只是启发。 Len Silverston的数据模型资源手册系列卷1包含普遍适用的数据模型(员工,账户,运输,采购等), 第2卷包含行业特定的数据模型(会计,医疗保健等), 第3卷提供数据模型模式。 最后,虽然这 ... -
每当需要基于switch语句调用不同的操作时,请考虑使用定义操作接口的抽象类和实现该操作的实现类。 在您的情况下, databaseEngine是一个命名数据库的String。 而是创建一个抽象类DatabaseEngine并定义createDatabase类的操作: public abstract class DatabaseEngine { public abstract void createDatabase(String databaseName); public abst ...
-
具有多个后端和不同数据库设计的数据访问层(Data Access Layer with Multiple Backends and Different Database Designs)[2022-04-17]
我们已在我们的一个项目中实施了此功能。 我不确定这是最好的解决方案,但到目前为止它已经为我们工作。 但是,我们有一个基于CodeSmith模板的自定义DAO图层,可以为我们生成CRUD类。 实质上,我们创建了一个代表所有用户的连接代理的单例。 当用户登录时,他们选择想要连接的数据库(尽管一些IP过滤缩小了他们的选项,理想情况下为1)。 登录存储连接令牌和关联的用户,生成的DAO层的基类调用连接代理来检索适当的连接字符串。 这样,每次调用DAO对象时,都会在DAO对象尝试连接到数据库之前收集连接字符串。 We ... -
这取决于。 如果这些其他数据库具有相同的20+表单和相同的50+视图,则通过模板创建和刷新设计是完成此操作的最佳方式。 另一方面,如果你的意思是你已经为格式化表单,操作栏,视图,表格等提出了一套标准,那么你手头的任务就大不相同了。 如果您确实在数据库中有一些相同(或应该相同)的文字Notes设计元素(表单,视图,子表单),则可以为这些单独的元素分配模板,并使用模板来刷新这些元素。 如果不相似的元素很少,您可以为数据库分配模板,但要么豁免不同的元素,要么将它们标记为从不同的模板继承。 因此,它取决于当前数据库 ...
-
最简单的技巧是不要调用基类方法。 相反,让继承的类使用专门的查询来获取可能一次性的数据。 如果您的要求是降低查询数量,oop对此没有任何魔力。 然后,另一个选择是拥有一个缓存代理 ,这是一个处理缓存的常规设计模式。 The simplest trick would be to not to call the base class method. Instead, let the inherited class use a specialized query to get the data in possib ...
-
评估 首先是审计,然后是具体答案。 这不是数据模型。 这不是数据库。 它是一桶鱼,每条鱼画成一个长方形,一条鱼的鳍在另一条鱼的鳃中被捕获,有一条鱼线。 有大量的重复,以及大量缺失的元素。 作为一个例子来学习关于数据库设计的任何事情完全不值得。 根本没有标准化; 这些文件是非常不完整的(参见迈克的回答,还有一百个这样的问题)。 other_details和eg.s破解我。 每个元素都需要被标识和存储: StreetNo, ApartmentNo, StreetName, StreetType等,而不是line ...
-
只需将上下文设为通用 将通用存储库更改为例如: public class GenericRepository
where TContext : DbContext where TEntity : class { internal TContext context; internal DbSet dbSet; public GenericRepositor ...