回想一年半前学数据库的时候是找的培训视频看的,大概10天视频(有一半多时间关于数据库操作的winform)的内容看完后数据库这块就没有了,还以为自己学的挺好,现在想想真是傻的可爱。虽然以ADO.NET为基础的EF挺好用的,但抽时间好好巩固下基础我觉得很重要。不废话了,ADO.NET提供对SQL、Oracle和MySql等数据库的访问操作,它有2个重要的组成部分:.NET数据提供程序和数据集DataSet。
1.什么是ADO.NET
.NET数据提供程序就是一个类集,本质的功能就是用于连接数据库、执行命令和检索结果,它可以理解为数据库与应用程序的一个接口层。主要的核心对象有4个,所有的.NET数据提供程序都实现了这几个对象各自的版本,附加了各自的前缀。
Connection对象:用于连接数据源。
Command对象:对数据源执行命令。
DataReader对象:在只读和只写的连接模式下从数据源读取数据。
DataAdapter对象:读取数据并使用所读取的数据填充数据集对象。
DataSet则是为独立于任何数据源的数据访问而设计,它可以用于多种不同的数据源。DataSet是一个集合,每一个子集则是DataTable对象,DataTable对象有数据行和数据列以及有关DataTable对象中的数据的主键、外键、约束和关系信息组成。我看的一本书举了一个很好的例子,我们可以想象数据库好比水源,存储了大量的数据,Connection对象好比进水管,通过它保持与水的接触并在需要时通过进水管抽水;Command对象则扮演着抽水机的角色,它为抽水提供执行方法;DataAdapter和DataReader就像输水管,负责水的传输任务;DataSet则是一个大水池,用于存放从水源里抽取的数据。
通过上面我们知道通过Connection与数据库建立连接或断开连接,对于SQL这个对象则是SqlConnection,Oracle则是OracleConnection,此外还有MySqlConnection等。
(1)连接SQL,string conStr="data source=127.0.0.1;Database=DataBase;user id=sa;password=123456";
SqlConnection connection=new SqlConnection(conStr);
connection.Open();
(2)对于OracleConnection对象则与SQL基本相同。
(3)在.Net中连接数据库有2种方法:ODBC连接器和OleDbConnection连接器。ODBC连接器是一个符合ODBC标准的交互平台,是.NET访问MySql的首选。首先需要得到MySql.Data.MySqlClient这个命名空间,引入后与SqlConnection基本相同。
从上面的分类可以看出写法基本一样,除了类名需要使用各自对应的类,这种统一的编程模型使编程变得很简单。
2.Command
前面说到Command相当于抽水机,它控制“抽水”,对于数据库来说这个对象封装了我们想要操作的各种操作数据库的命令,也就是SQL语句。
//使用command对数据库进行操作
string str="连接数据库字符串"; SqlConnection connection = new SqlConnection(str); string strQuery1 = ""; string strQuery2 = ""; connection.Open(); //开始数据库事务,保证数据库的ACID:原子性、一致性、隔离性和持久性
SqlTransaction trans = connection.BeginTransaction(); //建立SqlCommand与SqlConnection的关联,除了使用构造函数,还有下面两种写法 //command.Connection=connection; command=connection.CreateCommand();
SqlCommand command = new SqlCommand(strQuery1, connection, trans); try { int rows = command.ExecuteNonQuery(); command.CommandText = strQuery2; //设置SqlCommand的查询文本 //SqlCommand主要有4种方法
SqlDataReader dr = command.ExecuteReader(); //查询数据,返回一行或多行
rows = command.ExecuteNonQuery(); //返回受影响的行数
var data = command.ExecuteScalar(); //返回结果集中的第一行的第一列
object obj = command.ExecuteXmlReader(); //返回一个XmlReader对象
trans.Commit(); //提交数据库事务
connection.Close(); } catch { trans.Rollback(); }
当使用SqlCommand执行存储过程时,需要将SqlCommand.CommandType属性设置为StoredProcedure,这样显示设置就不需要在执行之前分析命令。
3.DataAdapter和DataReader
DataAdapter将数据加载到DataSet中,并使DataSet中数据的更改与数据源保持一致。
//使用command对数据库进行操作
string str = "连接数据库字符串"; SqlConnection connection = new SqlConnection(str); string strQuery1 = ""; connection.Open(); SqlCommand command = new SqlCommand(strQuery1, connection); DataSet ds=new DataSet(); //创建SqlDataAdapter的四种方式
SqlDataAdapter dataAdapter = new SqlDataAdapter(); SqlDataAdapter dataAdapter2 = new SqlDataAdapter(command); SqlDataAdapter dataAdapter3 = new SqlDataAdapter(strQuery1, connection); SqlDataAdapter dataAdapter4 = new SqlDataAdapter(strQuery1, str); dataAdapter.SelectCommand = command; dataAdapter.Fill(ds); connection.Close();
执行ExecuteReader方法时可以返回一个DataReader对象,DataReader以只进、只读方式返回数据,这样不会通过DataSet,这也是DataReader与DataAdapter的主要区别。但我们得到DataReader对象后,可以使用Read方法去读取每一行的数据。如果我们采用Read方法去得到数据,有一个很麻烦的事情那就是经常需要转换,其实DataReader为我们提供了一个非常便利的类型访问器,比如DataReader对象为dr,我们可以使用dr.GetString(“索引”),这样是直接返回string类型的。还有一点要注意,使用dr后要调用Close方法,说到关闭还有一个显示关闭Connection的方法,那就是将CommandBehavior.CloseConnection传递给ExecuteReader方法,这样的话调用dr.Close()时相应的连接就关闭了。最好的方式是我们写这方面的程序习惯性的加上using语句块,这样就不会出错了。
4.DataSet
这个类是ADO.NET中最核心的成员之一,是各种基于.NET平台的应用程序存储数据的数据池。DataSet最大的优点是离线或连接都可以操作数据,这样就可以大大减小服务器数据库的连接线程,当然离线时,如果进行的数据量操作比较大的话,真真更新到数据库时应该是很消耗性能的。DataSet的基本工作过程为:应用程序一般并不直接对数据库进行操作(使用存储过程除外),而是将数据全部填入DataSet对象后,客户端则是对DataSet进行操作,然后通过DataSet来和数据适配器将更新的数据同步到数据库中。一个DataSet由多个DataTable组成,一个DataTable就相当于一张数据表。具体用法如下。
DataSet ds=new DataSet(); DataTableCollection dtc = ds.Tables; DataTable dt = dtc[1]; //获取所有行、满足条件的行、满足条件且排序、满足特定条件
DataRow[] rows = dt.Select(); DataRow[] rows1 = dt.Select("ID>20"); DataRow[] rows2 = dt.Select("ID>20","ID DESC"); DataRow[] rows3 = dt.Select("ID>20", "ID DESC",DataViewRowState.ModifiedCurrent); //我们在使用SQL时,还可以轻松地对数据进行Sum、Aver、Count等操作来获得统计结果,这需要使用到Compute函数
object c = dt.Compute("sum(ID)", "age<60");//得到年龄小于60的ID的总和,当然它的功能终究是没有SQL强大的
5.封装SqlHelper
下面是我写的一个封装数据库操作的类
class SqlHelper { #region connstr
//2.WinForm项目,请添加对“System.Configuration”的引用 //2.1.对配置文件connectionStrings节进行读取
static string connstr = System.Configuration.ConfigurationManager.ConnectionStrings["connStr"].ConnectionString; #endregion
#region 查询数据库返回一张表 + static DataTable ExecuteDataTable(string sql, params SqlParameter[] parameters)
/// <summary>
/// 查询数据库返回一张表 /// </summary>
public static DataTable ExecuteDataTable(string sql, params SqlParameter[] parameters) { //创建一个零时的数据集,在内存里
DataSet ds = new DataSet(); //创建一个适配器对象,
SqlDataAdapter adapter = new SqlDataAdapter(sql, connstr); //给适配器对象的查询命令对象添加参数
adapter.SelectCommand.Parameters.AddRange(parameters); try { //填充数据集
adapter.Fill(ds); return ds.Tables[0]; } catch//如果捕捉错误,那么就返回null
{ return null; } } #endregion
#region 返回受影响的行数 ExecuteNonQuery(string sql, params SqlParameter[] parameters)
/// <summary>
/// 返回受影响的行数 /// </summary>
public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters) { using (SqlConnection conn = new SqlConnection(connstr)) { using (SqlCommand cmd = new SqlCommand(sql, conn)) { cmd.Parameters.AddRange(parameters); conn.Open(); return cmd.ExecuteNonQuery(); } } } #endregion
#region 返回查询结果 object ExecuteScalar(string sql, params SqlParameter[] parameters)
/// <summary>
/// 返回查询结果 /// </summary>
public static object ExecuteScalar(string sql, params SqlParameter[] parameters) { using (SqlConnection conn = new SqlConnection(connstr)) { using (SqlCommand cmd = new SqlCommand(sql, conn)) { cmd.Parameters.AddRange(parameters); conn.Open(); return cmd.ExecuteScalar(); } } } #endregion }