ADO.NET入门教程(七) 谈谈Command对象高级应用

摘要

在上一篇文章《你必须知道的ADO.NET(六) 谈谈Command对象与数据检索》中,我详细讲解了Command对象的基础知识以及基本用法。作为ADO.NET中最具执行力的对象,Command对象实属变幻莫测。在本文中,我将与大家一起探讨Command对象的高级应用与技巧。


目录

  • 异步执行命令
  • 请使用参数化查询
  • 获取插入行的ID
  • 总结

1. 异步执行命令

      在ADO.NET 2.0版本之前,执行Command对象命令时,需要等待命令完成才能执行其他操作。比如,执行ExcuteNonQuery()方法,应用程序将会保持阻塞,直到数据操作成功完成或者异常终止以及连接超时。在ADO.NET 2.0版本引入异步执行特性,显然,ADO.NET更稳健,更完美了。

异步执行的根本思想是,在执行命令操作时,无需等待命令操作完成,可以并发的处理其他操作。ADO.NET提供了丰富的方法来处理异步操作,BeginExecuteNonQuery和EndExcuteNonQuery就是一对典型的为异步操作服务的方法。BeginExecuteNonQuery方法返回System.IAsyncResult接口对象。我们可以根据IAsyncResult的IsCompleted属性来轮询(检测)命令是否执行完成。还是来看一个简单的实例把!这个实例采用了《你必须知道的ADO.NET(六) 谈谈Comand对象与数据检索》中的数据库和数据表。在这个实例中,我们将在tb_SelCustomer中插入500行数据,并计算执行时间。代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Data;//必须引入
 6 using System.Data.SqlClient;//必须引入
 7 
 8 namespace Command
 9 {
10     class Program
11     {
12         static void Main(string[] args)
13         {
14             SqlConnectionStringBuilder connStr = new SqlConnectionStringBuilder();
15             connStr.DataSource = @".\SQLEXPRESS";
16             connStr.IntegratedSecurity = true;
17             connStr.InitialCatalog = "db_MyDemo";
18             connStr.AsynchronousProcessing = true;//必须显示说明异步操作
19       
20             StringBuilder strSQL = new StringBuilder();
21 
22             //插入100个测试客户
23             for (int i = 1; i <= 500; ++i)
24             {
25                 strSQL.Append("insert into tb_SelCustomer ");
26                 strSQL.Append("values('");
27                 string name = "测试客户" + i.ToString();
28                 strSQL.Append(name);
29                 strSQL.Append("','0','0','13822223333','liuhaorain@163.com','广东省深圳市宝安区',12.234556,34.222234,'422900','备注信息'); ");
30             }
31 
32             using (SqlConnection conn = new SqlConnection(connStr.ConnectionString))
33             {
34                 conn.Open();
35                 SqlCommand cmd = new SqlCommand(strSQL.ToString(), conn);
36 
37                 IAsyncResult pending = cmd.BeginExecuteNonQuery();//开始执行异步操作
38                 double time = 0;
39 
40                 //检查异步处理状态
41                 while (pending.IsCompleted == false)
42                 {
43                     System.Threading.Thread.Sleep(1);
44                     time++;
45                     Console.WriteLine("{0}s", time * 0.001);
46                 }
47 
48                 if (pending.IsCompleted == true)
49                 {
50                     Console.WriteLine("Data is inserted completely...\nTotal coast {0}s", time * 0.001);
51                 }
52 
53                 cmd.EndExecuteNonQuery(pending);//结束异步操作
54             }
55 
56             Console.Read();
57         }
58     }
59 }

 处理结果如下:

2. 请使用参数化查询

      在ADO.NET中,查询语句是以字符串的形式传递给外部数据库服务器的。这些字符串不仅包含了基本命令关键字,操作符,还包含了限制查询的数值。与其他编程语言不同,.NET是基于强类型来管理查询字符串数据的。通过提供类型检查和验证,命令对象可使用参数来将值传递给 SQL 语句或存储过程。 与命令文本不同,参数输入被视为文本值,而不是可执行代码。 这样可帮助抵御“SQL 注入”攻击,这种攻击的攻击者会将命令插入 SQL 语句,从而危及服务器的安全。参数化命令还可提高查询执行性能,因为它们可帮助数据库服务器将传入命令与适当的缓存查询计划进行准确匹配。

      对于不同的数据源来说,Parameter对象不同,但都派生自DbParameter对象。下表列举了不同数据源对应的Parameter对象。

数据提供程序

对应Paramter对象

命名空间

SQLServer 数据源

使用SqlParamter对象

System.Data.SqlClient.SqlParameter

Ole DB 数据源

使用OleDbParameter对象

System.Data.OleDb.OleDbParameter

ODBC 数据源

使用OdbcParamter对象

System.Data.Odbc.OdbcParameter

Oracle数据源

使用OracleParameter对象

System.Data.OracleClient.OracleParameter

      Paramter对象的属性很多,其中常见而且非常重要的主要有以下几个:

  • DbType: 获取或设置参数的数据类型。
  • Direction: 获取或设置一个值,该值指示参数是否只可输入、只可输出、双向还是存储过程返回值参数。
  • IsNullable: 获取或设置一个值,该值指示参数是否可以为空。
  • ParamteterName: 获取或设置DbParamter的名称。
  • Size: 获取或设置列中数据的最大大小。
  • Value: 获取或设置该参数的值。

 以SQL Server为例,SqlCommand对象包含一个Paramters集合,Paramters集合中包含了所有所需的SqlParamter对象。当执行命令时,ADO.NET同时将SQL文本,占位符和参数集合传递给数据库。

提示: 对于不同的数据源来说,占位符不同。SQLServer数据源用@parametername格式来命名参数,OleDb以及Odbc数据源均用问号(?)来标识参数位置,而Oracle则以:parmname格式使用命名参数。

下面我们看一个实例,修改 测试顾客1 的基本信息。修改的基本信息如下:

  1. 电话号码(Phone):18665691100
  2. 电子邮箱(Email):test@163.com
  3. 地址(ContactAddress):中国深圳市南山区

代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Data;
 6 using System.Data.SqlClient;
 7 
 8 
 9 namespace Command2
10 {
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             //构造连接字符串
16             SqlConnectionStringBuilder connStr = new SqlConnectionStringBuilder();
17             connStr.DataSource = @".\SQLEXPRESS";
18             connStr.IntegratedSecurity = true;
19             connStr.InitialCatalog = "db_MyDemo";
20 
21             //拼接SQL语句
22             StringBuilder strSQL = new StringBuilder();
23             strSQL.Append("Update tb_SelCustomer Set ");
24             strSQL.Append("Phone = @Phone,");
25             strSQL.Append("Email = @Email,");
26             strSQL.Append("ContactAddress = @Address ");
27             strSQL.Append("where Name = @Name");
28 
29             using (SqlConnection conn = new SqlConnection(connStr.ConnectionString))
30             {
31                 SqlCommand cmd = new SqlCommand(strSQL.ToString(), conn);
32 
33                 //构造Parameter对象
34                 SqlParameter para1 = new SqlParameter("@Phone", SqlDbType.VarChar, 12);
35                 SqlParameter para2 = new SqlParameter("@Email",SqlDbType.VarChar,50);
36                 SqlParameter para3 = new SqlParameter("@Address",SqlDbType.VarChar,200);
37                 SqlParameter para4 = new SqlParameter("@Name",SqlDbType.VarChar,20);
38 
39                 //给Parater对象赋值
40                 para1.Value = "18665691100";
41                 para2.Value = "test@163.com";
42                 para3.Value = "中国深圳市南山区";
43                 para4.Value = "测试客户1";
44 
45                 //添加到Parameters集合中
46                 cmd.Parameters.Add(para1);
47                 cmd.Parameters.Add(para2);
48                 cmd.Parameters.Add(para3);
49                 cmd.Parameters.Add(para4);
50 
51                 try
52                 {
53                     conn.Open();
54                     cmd.ExecuteNonQuery();
55                     Console.WriteLine("Update Success...");
56                 }
57                 catch(Exception ex)
58                 {
59                     Console.WriteLine("{0}",ex.Message);
60                 }
61             }
62 
63             Console.Read();
64         }
65     }
66 }

 看了上面的代码不知大家有何感想,是否觉得太多繁琐呢?的确,我们可以用更简洁的方法来实现。具体方法是,我们可以先构造Parameter对象数组,然后遍历添加到Command对象的Paramters集合中。代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Data;
 6 using System.Data.SqlClient;
 7 
 8 
 9 namespace Command2
10 {
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             //构造连接字符串
16             SqlConnectionStringBuilder connStr = new SqlConnectionStringBuilder();
17             connStr.DataSource = @".\SQLEXPRESS";
18             connStr.IntegratedSecurity = true;
19             connStr.InitialCatalog = "db_MyDemo";
20 
21             //拼接SQL语句
22             StringBuilder strSQL = new StringBuilder();
23             strSQL.Append("Update tb_SelCustomer Set ");
24             strSQL.Append("Phone = @Phone,");
25             strSQL.Append("Email = @Email,");
26             strSQL.Append("ContactAddress = @Address ");
27             strSQL.Append("where Name = @Name");
28 
29             using (SqlConnection conn = new SqlConnection(connStr.ConnectionString))
30             {
31                 SqlCommand cmd = new SqlCommand(strSQL.ToString(), conn);
32 
33                 //构造Parameter对象
34                 SqlParameter[] paras = new SqlParameter[]{ 
35                     new SqlParameter("@Phone", SqlDbType.VarChar, 12),
36                     new SqlParameter("@Email", SqlDbType.VarChar, 50),
37                     new SqlParameter("@Address", SqlDbType.VarChar, 200),
38                     new SqlParameter("@Name", SqlDbType.VarChar, 20)
39                };
40 
41                 //给Parater对象赋值
42                 paras[0].Value = "18665691100";
43                 paras[1].Value = "test@163.com";
44                 paras[2].Value = "中国深圳市南山区";
45                 paras[3].Value = "测试客户1";
46 
47                 //遍历添加到Parameters集合中
48                 foreach (var item in paras)
49                 {
50                     cmd.Parameters.Add(item);
51                 }
52 
53                 try
54                 {
55                     conn.Open();
56                     cmd.ExecuteNonQuery();
57                     Console.WriteLine("Update Success...");
58                 }
59                 catch (Exception ex)
60                 {
61                     Console.WriteLine("{0}", ex.Message);
62                 }
63             }
64 
65             Console.Read();
66         }
67     }
68 }

 上面两种写法,结果完全相同。查询数据库,我们可以得到以下结果:

3. 如何获取插入行的ID?

      很多时候,我们需要知道插入行的ID是多少,以方便我们进行利用插入行的ID进行其他操作,比如在页面上的展示等等。当然实现的方法有很多种,比如利用C#的out修饰符修饰参数,我更倾向于用SQL Server数据库原生的OUTPUT关键字。OUTPUT关键字返回INSERT操作的一个字段(一般是主键ID)。因此我们只要结合OUTPUT关键字以及ExecuteScalar方法,就很容易得到插入行的主键。还是看一个简单的实例把!我们在tb_SelCustomer中插入一个新的顾客,并返回这个顾客的ID。代码如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Data;
 6 using System.Data.SqlClient;
 7 
 8 
 9 namespace Command2
10 {
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             //构造连接字符串
16             SqlConnectionStringBuilder connStr = new SqlConnectionStringBuilder();
17             connStr.DataSource = @".\SQLEXPRESS";
18             connStr.IntegratedSecurity = true;
19             connStr.InitialCatalog = "db_MyDemo";
20 
21             //拼接SQL语句
22             StringBuilder strSQL = new StringBuilder();
23             strSQL.Append("insert tb_SelCustomer(Name) ");
24             strSQL.Append("OUTPUT inserted.ID values(@Name)");
25 
26             using (SqlConnection conn = new SqlConnection(connStr.ConnectionString))
27             {
28                 SqlCommand cmd = new SqlCommand(strSQL.ToString(), conn);
29 
30                 SqlParameter para = new SqlParameter("@Name", SqlDbType.VarChar, 20);
31                 para.Value = "Kemi";
32                 cmd.Parameters.Add(para);
33 
34                 try
35                 {
36                     conn.Open();
37                     int insertedID = (int)cmd.ExecuteScalar();//获取单个值
38 
39                     Console.WriteLine("Inserted ID:{0}", insertedID);
40                 }
41                 catch (Exception ex)
42                 {
43                     Console.WriteLine("{0}", ex.Message);
44                 }
45             }
46 
47             Console.Read();
48         }
49     }
50 }

运行结果如下:

4. 总结

      简言之,Command对象的核心作用是执行命令。在执行命令过程中,面临的情况是十分复杂的。尽管如此,Command对象拥有优越的人力资源(属性和方法),来应对一切可能发生的事。可以说,Command对象的稳定发挥,为ADO.NET打下了扎实的根基。到目前为止,我们基本上了解ADO.NET DataProvider组件所有的内容。因此,后面我将重点讲述ADO.NET的心脏----DataSet以及如何将数据源本地化。另外,我非常期待能得到您的推荐和关注。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏丑胖侠

《Drools7.0.0.Final规则引擎教程》番外实例篇——FactHandler使用案例

背景 在使用具体的业务使用中,我们经常会通代码对Fact对象进行操作,Drools为我们提供了FactHandler来获取对象的句柄,通过此返回值可以对Work...

27950
来自专栏tkokof 的技术,小趣及杂念

Sweet Snippet 系列之 有序列表

很朴素的一种想法,为了维持 List 有序,我们可以在 Add 操作之后进行 Sort 操作(Remove 操作后不需要重新 Sort):

5210
来自专栏GIS讲堂

一个GISER 6.7的祝福

一年一度的高考今天开始了,回想10年前,那是我第一次高考;10年后,作为一个GISER,在此给大家献上一个GISER的祝福,祝愿各位考生:考神附体,考完报考GI...

15340
来自专栏更流畅、简洁的软件开发方式

我的数据访问类(第二版)—— for .net2.0 (二)

下面写一下相对来说不变的地方 SQL语句部分,改成了静态函数的形式。 using System; using System.Collections.Generi...

15680
来自专栏技术博客

C#函数方法集

1、DateTime 数字型 System.DateTime currentTime=new System.DateTime();

14420
来自专栏大内老A

我的WCF之旅(7):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的继承

当今的IT领域,SOA已经成为了一个非常时髦的词,对SOA风靡的程度已经让很多人对SOA,对面向服务产生误解。其中很大一部分人甚至认为面向服务将是面向对象的终结...

19650
来自专栏菩提树下的杨过

c#:使用using关键字自动释放资源未必一定就会有明显好处

记录这篇文章的灵感来源来自今天下班前与同事的小小争论,我现在开发的一个项目中,有这样一段代码: public string ToXML() { ...

22480
来自专栏jessetalks

async & await 的前世今生(Updated)

async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是asyn...

351110
来自专栏草根专栏

asp.net web api 2.2 基础框架(带例子)

简介 这个是我自己编写的asp.net web api 2.2的基础框架,使用了Entity Framework 6.2(beta)作为ORM。 该模板主要采用...

62290
来自专栏草根专栏

使用C# (.NET Core) 实现状态设计模式 (State Pattern)

51450

扫码关注云+社区

领取腾讯云代金券