首页 > 代码库 > ADO.NET学习笔记-读写数据

ADO.NET学习笔记-读写数据

1. DbCommand对象
要读写数据,一是需要有效的数据链接,二是需要DbCommand对象向数据源传递SQL命令。DbCommand对象包含的命令可以是DML数据操作语言,也可以是DDL数据定义语言。创建DbCommand的最好方式是先创建DbConnection,然后使用DbConnection的CreateCommand()方法,这样创建的DbCommand与DbConnection之间最为匹配。DbCommand必备的两个重要属性为CommandText和CommandType,示例代码如下:
static void Main()
        {
            var conString = ConfigurationManager.ConnectionStrings["TestApp.Properties.Settings.toucaiConnectionString"].ConnectionString;
            var conn = new MySqlConnection(conString);
            var cmd = conn.CreateCommand();
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = "select count(*) from product";
           
            conn.Open();
            long count = (long)cmd.ExecuteScalar();
            Console.WriteLine("共有" + count + "条商品条记录");
            conn.Close();
           
        }
 
2. DbParameter对象
如果CommandType属性的值为CommandType.Procedure,则多半需要使用DbParameter对象,因为大部分的SQL过程都需要输入或输出参数。例如如果服务器上有过程product_name,其代码如下:
CREATE DEFINER=`lqs2011`@`%` PROCEDURE `product_name`(
       IN oPrice DECIMAL(8, 2)
)
BEGIN
     SELECT prodName, outPrice
     FROM product
     WHERE outPrice = oPrice AND brandID = 1;
END
可以看出此过程要求一个输入参数oPrice,用于指定零售价格,示例程序如下:
using (var conn = new MySqlConnection(conString))
            {
                var cmd = conn.CreateCommand();
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.CommandText = "product_name";
                var param = cmd.CreateParameter();
                param.ParameterName = "@oPrice";
                param.Value = "398.00";
                cmd.Parameters.Add(param);
 
                conn.Open();
                var reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    Console.WriteLine("{0,-15}\t{1,15}", reader[0], reader[1]);
                }
            }
需要注意的是,不同的数据提供程序(Provider)对参数的要求不同,例如SQL SERVER要求参数的名称必须与数据库过程中的名称一致,于是顺序就不重要了;而OLEDB则要求参数的顺序必须与数据库过程中的参数相一致,于是参数名称就不重要了。为满足不同数据提供程序的要求,我们最好名称及顺序都与数据库过程保持一致。
 
3. DbCommand的执法
常用的命令执法方法有ExecuteNonQuery()、ExecuteReader()和ExecuteScalar()三种,其中:
  • ExecuteNonQuery()顾名思义是执法非查询语句的,例如用DDL语言来创建、更改或删除数据库对象等,此方法不会返回数据行,但会返回一个整形数据,用于显示受影响的行的数目。
  • ExecuteReader()方法返回一个DbDataReader实例,这是一个只读只进的,存在于服务器端的指针。第2条中的代码已经演示了此方法的执法过程。
  • ExecuteScalar()方法返回首行首列的值,一般也只有一行一列,即返回一个标题值,而非一个列对象。如前面的
    long count = (long)cmd.ExecuteScalar()
    cmd.ExecuteScalar()返回的是一个object对象,装箱后成为一个长整形值。在需要返回一个确定的值时,使用此方法可大幅提升性能。
 
 
4. DbDataReader对象
前面已经提到,DbDataReader是一个只读只进的,存在于服务器端的指针,性能非常优异,常用于填充ListBox、DropDownList等控件数据。在运行报表时,也可使用此对象来获取远程服务器端的数据来显示。当然,因为此对象得到的数据是只读的,所以如果需要修改数据并将修改后的数据回写到远程数据库,就不能再用DbDataReader对象了,而应使用DbDataAdapter对象。
DbDataReader最主要的方法为Read(),用于将远程数据加载至此对象的缓冲中。示例代码如下:
using (var conn = new MySqlConnection(conString))
            {
                var cmd = conn.CreateCommand();
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = "SELECT prodName, outPrice FROM product";
 
                conn.Open();
                var reader = cmd.ExecuteReader();
                var tbProducts = new DataTable();
                tbProducts.Load(reader, LoadOption.Upsert);
                cmbProducts.DataSource = tbProducts;
                cmbProducts.DisplayMember = "prodName";
                cmbProducts.ValueMember = "prodName";
            }
注意,在使用DataTable加载数据时,有一个加载选项,即LoadOption枚举类型,用于定义本地数据与远程数据不一致时的行为,共有3个值,分别为:
  • OverwriteChanges:放弃本地更改
  • PreserveChanges:保留本地更改
  • Upsert:目的是从远程下载数据,以远程数据为主
5. DbDataAdapter对象
此对象是ADO.NET进行数据同步的核心对象,用于在本地数据和远程数据源间进行数据同步。在获取数据时,DbDataAdapter拥有一个SelectCommand属性,SelectCommand属性又有一个合法的DbCommand对象,这个DbCommand对象又有一个合法可用的数据链接。DbCommand对象又有一个ExecuteReader方法,执法后得到一个DbDataReader对象,用于填充DataTable对象。
DbDataAdapter还拥有InsertCommand, UpdateCommand和DeleteCommand属性,它们均可能包含DbCommand对象,如果仅仅是从远程数据源读取数据而不做任何更改并回传同步,则不必创建这些属性,但如果需要更改并回传数据,则需同时创建上述4种命令(含SelectCommand)。
DbDataAdapter在进行数据同步前会检查数据链接情况,如果链接没有打开,就自动打开链接,完成工作后自动关闭链接,但还是建议手动打开并关闭链接,一是有良好的习惯,二是在同时有多个DbDataAdapter工作时,手动打开链接能提升性能。
 
6. 使用DbDataAdapter的Fill()方法
此方法用于将远程DataSet数据填充到本地DataTable对象。示例代码如下:
            using (var conn = new MySqlConnection(conString))
            {
                var cmd = conn.CreateCommand();
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = "SELECT prodName, outPrice FROM product"; //初始化SelectCommand
 
                conn.Open();                
                var da = new MySqlDataAdapter(cmd);
                var ds = new DataSet();
                da.Fill(ds, "product"); //用于将远程product表中的数据填充至本地DataSet中
                cmbProducts.DataSource = ds.Tables[0];
                cmbProducts.DisplayMember = "prodName";
            }
编程建议,如果需回传修改后的数据,最好为每个DataTable创建单独的DataAdapter,如果不需回传数据,则使用DbDataReader就够了。
 
7. 使用update()方法保存修改至远程数据源
update()方法保存修改至远程数据源的过程如下:
  • 从本地DataTable中找出更改内容
  • 使用InsertCommand, UpdateCommand或是DeleteCommand在远程数据源中执行更改
  • 执行更改是按行进行的(on a row-byrow basis)
  • update()方法判断行是否被更改的依据是查看行的RowState属性,如果行属性不为Unchanged,则执行更改
前面已经讲过,要修改回写数据,DbDataAdapter必须同时拥有SelectCommand, InsertCommand, UpdateCommand和DeleteCommand4种命令,创建这4种命令的方法有3种:
  • 手工分别创建DbCommand对象(一般不用)
  • 使用DataAdapter配置向导(DataAdapter Configuration Wizard,在向窗体中添加DataAdapter时自动打开)
  • 使用DbCommandBuilder对象,但需要DataAdapter有一个合法可用的SelectCommand对象
示例代码如下:
using (var conn = new MySqlConnection(conString))
            {
                var cmd = conn.CreateCommand();
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = "SELECT * FROM product";
                var da = new MySqlDataAdapter(cmd);
                var ds = new DataSet();
                var cmdBuilder = new MySqlCommandBuilder(da);
               
                conn.Open();
                da.Fill(ds, "product");
                var dt = ds.Tables[0];
                var updateRow = dt.Select("innerBar = ‘ZZZ002‘")[0];
                updateRow["outPrice"] = (decimal)8.0;
                int count = da.Update(ds, ds.Tables[0].TableName);
                if(count > 0)
                    Console.WriteLine("OK");
            }
 
8. 打包提交更改至远程数据库
系统默认是逐个向远程数据库提交更改,通过设置DataAdapter的UpdateBatchSize属性值为0可让系统将尽可能多的数据行打包提交,从而大幅提升性能。
 
9. DbProviderFactory类
到目前为止,我们看到的代码都是与具体的provider相关联的,比如MySqlConnection对象,是由MySQL Provider提供的,于是也只能用于连接MySQL数据库,要实现代码与具体的远程数据源类型无关的代码,需用到DbProviderFactory类。
 

ADO.NET学习笔记-读写数据