热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#通用数据库操作类

ADO.NET操作使用ADO.NET的方式操作数据库时,对于经常需要操作不同数据库的同学,需要对不同的数据库翻来覆去地写操作类。对ADO.NET,操作数据库需要有几个核心的东西(以MySql为例):M

ADO.NET操作

使用ADO.NET的方式操作数据库时,对于经常需要操作不同数据库的同学,需要对不同的数据库翻来覆去地写操作类。


对ADO.NET,操作数据库需要有几个核心的东西(以MySql为例):

MySqlConnection

负责mysql的连接,在操作mysql前,需要先获得连接。

MySqlCommand

负责具体命令的类,具体需要执行的sql的语句需要放到它的CommandText下。

MySqlDataAdapter

对于查询数据,可以选择使用DataAdapter将数据一次性取出到DataSet或者DataTable中。

MySqlDataReader

对于查询数据,同样可以使用Reader类对数据进行读取,与Adapter不同,Reader一次取得一条数据,可以在数据获取的过程中执行代码,而不需要等待数据一次性取出。

对于mysql有以上的几个主要类,对于SQLite、SQL Server,同样类似。
可以使用一个类来将他们包装,然后编译成dll,这样如果需要操作不同的数据库,只需要通过工厂创建不同的类即可。

提取相同点

使用ADO.NET方式的数据库驱动,他们都满足这么几个特点:

  • 上面列出的核心类都提供,而且都从对应的基类继承,例如MySqlConnection从SqlConnection继承。
  • Command类可以通过对应Connection的CreateCommand方法生成。

那么问题就简单了,我们只要操作他们的基类就可以了。然后他们的引用通过nuget获得,这样就能正常编译。

//主要代码

///
/// 可以根据支持的Sql类型增加或删除类型,需要增加或删除对应的GetConnection和GetDbDataAdapter方法。
///

public enum SqlType
{
SqlServer,
MySql,
PostgresQL,
Oracle,
SQLite,
//对ODBC方式需要格外注意,目标系统必须预先安装有对应的数据驱动,如果使用DSN,那么还需要使用配置ODBC数据源
Odbc
}
///
/// 使用ADO.NET控制对数据库的基本访问方法,对同一个活动对象(不关闭)线程安全。
///

public class SqlManipulation : IDisposable
{

public SqlManipulation(string strDSN, SqlType sqlType)
{
_sqlType = sqlType;
_strDSN = strDSN;
}

#region private variables
private SqlType _sqlType;
private string _strDSN;
private DbConnection _conn;
private bool _disposed;
#endregion

private DbConnection GetConnection()
{
DbConnection conn;
switch (_sqlType)
{
case SqlType.SqlServer:
cOnn= new SqlConnection(_strDSN);
return conn;
case SqlType.MySql:
cOnn= new MySqlConnection(_strDSN);
return conn;
case SqlType.PostgresQL:
cOnn= new NpgsqlConnection(_strDSN);
return conn;
case SqlType.Oracle:
cOnn= new OracleConnection(_strDSN);
return conn;
case SqlType.SQLite:
cOnn= new SQLiteConnection(_strDSN);
return conn;
case SqlType.Odbc:
cOnn= new OdbcConnection(_strDSN);
return conn;
default:
return null;
}
}

private DbDataAdapter GetDbDataAdapter(string sql)
{
DbDataAdapter adp;
switch (_sqlType)
{
case SqlType.SqlServer:
adp = new SqlDataAdapter(sql, _conn as SqlConnection);
return adp;
case SqlType.MySql:
adp = new MySqlDataAdapter(sql, _conn as MySqlConnection);
return adp;
case SqlType.PostgresQL:
adp = new NpgsqlDataAdapter(sql, _conn as NpgsqlConnection);
return adp;
case SqlType.Oracle:
adp = new OracleDataAdapter(sql, _conn as OracleConnection);
return adp;
case SqlType.SQLite:
adp = new SQLiteDataAdapter(sql, _conn as SQLiteConnection);
return adp;
case SqlType.Odbc:
adp = new OdbcDataAdapter(sql, _conn as OdbcConnection);
return adp;
default:
return null;
}
}

private DbCommand GetCommand(DbConnection conn, string strSQL)
{
DbCommand command = conn.CreateCommand();
command.CommandText = strSQL;
return command;
}

///
/// 初始化连接并打开
///

///
public bool Init()
{
try
{
_cOnn= GetConnection();
_conn.Open();
return true;
}
catch (Exception e)
{
//记录日志,退出
MessageBox.Show(e.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}

///
/// 执行SELECT查询语句,并返回DataTable对象。
///

/// 需要执行的sql语句
/// DataTable对象
public DataTable ExcuteQuery(string strSQL)
{
DbDataAdapter adp = GetDbDataAdapter(strSQL);
DataTable dt = new DataTable();
try
{
adp.Fill(dt);
}
catch (Exception e)
{
//记录日志,并返回空
MessageBox.Show(strSQL + "\n" + e.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
return dt;
}

///
/// 执行非Select语句,包括UPDATE DELETE INSERT
///

/// 需要执行的sql语句
/// 受影响的行数
public int ExcuteNonQuery(string strSQL)
{
//实例化OdbcCommand对象
DbCommand myCmd = GetCommand(_conn, strSQL);

try
{
//执行方法
return myCmd.ExecuteNonQuery();
}
catch (Exception e)
{
//记录日志,并返回0
MessageBox.Show(strSQL + "\n" + e.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return 0;
}
}

///
/// 通过事务批量执行非查询SQL语句
///

/// 需要批量执行的SQL
/// 受影响的行数,发生回滚则返回-1
public int ExecuteNonQueryTransaction(List strSQLs)
{
DbCommand myCmd = GetCommand(_conn, "");
int sumAffected = 0;

DbTransaction transaction = _conn.BeginTransaction();
myCmd.Transaction = transaction;

try
{
foreach (var n in strSQLs)
{
myCmd.CommandText = n;
sumAffected += myCmd.ExecuteNonQuery();
}
transaction.Commit();
return sumAffected;
}
catch (Exception e)
{
MessageBox.Show(e.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
transaction.Rollback();
return -1;
}
}
}
  • 由于不同数据库对数据类型的实现不同,不同数据库在操作command parameter上也有一些不同,所以暂时没有加入到此类中去。
  • 最开始,想使用反射来达到目的,可以避免switch分支,后来想起反射需要知道Assembly名称,写这段代码还不如直接switch。

完整项目代码github地址:https://github.com/circler3/DatabaseInvoke.git
(现在已经对mysql、sql server、posgresql、sqlite和ODBC方式支持)

未来的改进

  1. 考虑添加EF的支持(引用使用EF的程序,主程序app.config或者web.config需要添加配置项目)
  2. 代码重构
  3. 数据库现在是持续保持打开,拟增加其他选项

写在最后

程序比较简单,代码放在github上,欢迎交流。


推荐阅读
  • 本文总结了一些开发中常见的问题及其解决方案,包括特性过滤器的使用、NuGet程序集版本冲突、线程存储、溢出检查、ThreadPool的最大线程数设置、Redis使用中的问题以及Task.Result和Task.GetAwaiter().GetResult()的区别。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 本文探讨了使用JavaScript在不同页面间传递参数的技术方法。具体而言,从a.html页面跳转至b.html时,如何携带参数并使b.html替代当前页面显示,而非新开窗口。文中详细介绍了实现这一功能的代码及注释,帮助开发者更好地理解和应用该技术。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
  • 通过将常用的外部命令集成到VSCode中,可以提高开发效率。本文介绍如何在VSCode中配置和使用自定义的外部命令,从而简化命令执行过程。 ... [详细]
  • 在分析Android的Audio系统时,我们对mpAudioPolicy->get_input进行了详细探讨,发现其背后涉及的机制相当复杂。本文将详细介绍这一过程及其背后的实现细节。 ... [详细]
  • 网站访问全流程解析
    本文详细介绍了从用户在浏览器中输入一个域名(如www.yy.com)到页面完全展示的整个过程,包括DNS解析、TCP连接、请求响应等多个步骤。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 在C#编程中,数值结果的格式化展示是提高代码可读性和用户体验的重要手段。本文探讨了多种格式化方法和技巧,如使用格式说明符、自定义格式字符串等,以实现对数值结果的精确控制。通过实例演示,展示了如何灵活运用这些技术来满足不同的展示需求。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 在C#编程中,设计流畅的用户界面是一项重要的任务。本文分享了实现Fluent界面设计的技巧与方法,特别是通过编写领域特定语言(DSL)来简化字符串操作。我们探讨了如何在不使用`+`符号的情况下,通过方法链式调用来组合字符串,从而提高代码的可读性和维护性。文章还介绍了如何利用静态方法和扩展方法来实现这一目标,并提供了一些实用的示例代码。 ... [详细]
  • 本文深入解析了HTML框架集(FRAMESET)的使用方法及其应用场景。首先介绍了几个关键概念,如如何通过FRAMESET标签将主视图划分为多个独立的区域,每个区域可以加载不同的HTML文件。此外,还详细探讨了FRAMESET在实际开发中的优缺点,并提供了具体的实例代码,帮助开发者更好地理解和应用这一技术。 ... [详细]
author-avatar
my小甜心
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有