執行數據庫命令(Command對象)——ADO.NET學習&應用筆記之三

數據提供程序的Command類是IDBCommand接口的實現,通過Command來執行數據庫命令,數據庫數據的查詢、更新、插入都通過Command來實現。
Command的構造函數通常都有下面三種形式:
1, public xxxCommand();
2, public xxxCommand(string);
3, public xxxCommand(string,xxxConnection);

一般我們創建Command對象都通過類似於下面的語句來實現:
xxxConnection conn = new xxxConnection("myString");
xxxCommand myCmd = new xxxCommand("select * from orders",conn);

構造函數的兩個參數是SQL語句和Connection對象,創建了Command對象。

下面說明Command對象的執行,程序範例將採用SqlClient數據提供程序來訪問一個Sql Server的數據庫Northwind。

一、設置連接和SQL命令
Command類的屬性CommandText用來設置命令語句,Connection屬性用來設置連接對象。設置命令對象的數據連接和命令語句除了可以在通過創建對象時通過構造函數定義外,這兩個屬性設置和更改。
SqlConnection conn = new SqlConnection("Server=localhost;Database=Northwind;User ID=sa;PWD=sa");
conn.Open();
SqlCommand cmd = new SqlCommand("select * from [Orders]",conn);
cmd.CommandText = "delete [Orders] where [OrderID]=10248";

二、執行命令
建立了數據源的連接和設置了命令之後,Command對象執行SQL命令有三種方法:ExecuteNonQueryExecuteReaderExecuteScalar
使用ExecuteNonQuery執行命令不會返回結果集,只會返回語句影響的記錄行數,它適合執行插入、更新、刪除之類不返回結果集的命令。如果是SELECT語句,那麼返回的結果是-1,如果發生回滾這個結果也是-1。下面的程序範例對Orders表執行了更新並做了查詢。

using System;
using System.Data;
using System.Data.SqlClient;
public class myDataAccess{
 public static void Main(){
  SqlConnection conn = new SqlConnection("Server=localhost;Database=Northwind;User ID=sa;PWD=sa");
  SqlCommand cmd = new SqlCommand("update [Orders] set [OrderDate]='2004-9-1' where [OrderID]=10248",conn);
  try{
   conn.Open();
   int i = cmd.ExecuteNonQuery();
   Console.WriteLine(i.ToString() + " rows affected by UPDATE");
   cmd.CommandText = "select * from [Orders]";
   i = cmd.ExecuteNonQuery();
   Console.WriteLine(i.ToString() + " rows affected by SELECT");
  }
  catch(Exception ex){
   Console.WriteLine(ex.Message);
  }
  finally{
   conn.Close();
  }
 }
}

編譯執行後,返回:

使用ExecuteReader方法執行的命令,可以返回一個類型化的DataReader實例或者IDataReader接口的結果集。通過DataReader對象就能夠獲得數據的行集合,本文不準備詳細討論DataReader,關於DataReader的使用將來再說明。下面是一個例子。
using System;
using System.Data;
using System.Data.SqlClient;
public class myDataAccess{
 public static void Main(){
  SqlConnection conn = new SqlConnection("Server=localhost;Database=Northwind;User ID=sa;PWD=sa");
  SqlCommand cmd = new SqlCommand("select top 20 * from [Orders]",conn);
  SqlDataReader reader; //或者IDataReader reader;
  try{
   conn.Open();
   reader = cmd.ExecuteReader();
   while(reader.Read()){
    Console.WriteLine(reader[0].ToString());
   }
   reader.Close();
  }
  catch(Exception ex){
   Console.WriteLine(ex.Message);
  }
  finally{
   conn.Close();
  }
 }
}

編譯執行結果如下:

對於ExecuteReader方法,如果想獲得數據的記錄行數,可以通過select count(*)這樣的語句取得一個聚合的行集合。對於這樣求單個值的語句,Command對象還有更有效率的方法——ExecuteScalar。它能夠返回對應於第一行第一列的對象(System.Object),通常使用它來求聚合查詢結果。需要注意的是,如果需要把返回結果轉化成精確的類型,數據庫在查詢中就必須強制將返回的結果轉換,否則引發異常。下面是例子:

using System;
using System.Data;
using System.Data.SqlClient;
public class myDataAccess{
 public static void Main(){
  SqlConnection conn = new SqlConnection("Server=localhost;Database=Northwind;User ID=sa;PWD=sa");
  SqlCommand cmd = new SqlCommand("select count(*) from [Orders]",conn);
  try{
   conn.Open();
   int i = (int)cmd.ExecuteScalar();
   Console.WriteLine("record num : " + i.ToString());
   cmd.CommandText = "select cast(avg([Freight]) as int) from [Orders]";
   int avg = (int)cmd.ExecuteScalar();
   Console.WriteLine("avg : " + avg.ToString());
   cmd.CommandText = "select avg([Freight]) from [Orders]";
   avg = (int)cmd.ExecuteScalar(); //引發異常
   Console.WriteLine("avg : " + avg.ToString());
  }
  catch(Exception ex){
   Console.WriteLine(ex.Message);
  }
  finally{
   conn.Close();
  }
 }
}

編譯執行結果如下:

這個程序中,最後一個查詢將引發異常,因爲聚合返回的結果是float類型的,無法轉換。


三、參數化查詢
參數化的查詢能夠對性能有一定的優化,因爲帶參數的SQL語句只需要被SQL執行引擎分析過一次。Command的Parameters能夠爲參數化查詢設置參數值。Parameters是一個實現IDataParamterCollection接口的參數集合。
不同的數據提供程序的Command對參數傳遞的使用不太一樣,其中SqlClient和OracleClient只支持SQL語句中命名參數而不支持問號佔位符,必須使用命名參數,而OleDb和Odbc數據提供程序只支持問號佔位符,不支持命名參數。
對於查詢語句SqlClient必須使用命名參數,類似於下面的寫法:
SELECT * FROM Customers WHERE CustomerID = @CustomerID --Oracle的命名參數前面不用@,使用(:),寫爲(:CustomerID)
而對於OleDb或者Odbc必須使用?佔位符,類似於下面的寫法:
SELECT * FROM Customers WHERE CustomerID = ?

下面以Sql Server爲範例,說明其使用方法:
using System;
using System.Data;
using System.Data.SqlClient;
public class myDataAccess{
 public static void Main(String[] args){
  SqlConnection conn = new SqlConnection("Server=localhost;Database=Northwind;User ID=sa;PWD=sa");
  SqlCommand cmd = new SqlCommand("select * from [Orders] where [OrderID]=@oid",conn);
  SqlDataReader reader;
  try{
   int param = Convert.ToInt32(args[0]);
   cmd.Parameters.Add("@oid",param);  //使用命名參數
   cmd.Parameters[0].Direction = ParameterDirection.Input;
   conn.Open();
   reader = cmd.ExecuteReader();
   while(reader.Read()){
    Console.WriteLine(reader[0].ToString());
   }
   reader.Close();
  }
  catch(Exception ex){
   Console.WriteLine(ex.Message);
  }
  finally{
   conn.Close();
  }
 }

編譯之後,執行結果如下:

對於OleDb或者Odbc數據提供程序的命令參數,只需要把參數按照佔位符從左到右的順序,匹配給Parameters集合就行了。 下面是程序範例:

using System;
using System.Data;
using System.Data.OleDb;
public class myDataAccess{
 public static void Main(String[] args){
  OleDbConnection conn = new OleDbConnection("Provider=SQLOLEDB;Server=localhost;Database=Northwind;User ID=sa;PWD=sa");
  OleDbCommand cmd = new OleDbCommand("select * from [Orders] where [OrderID]=? or [EmployeeID]=?",conn);
  OleDbDataReader reader;
  try{
   int param1 = Convert.ToInt32(args[0]);
   int param2 = Convert.ToInt32(args[1]);
   cmd.Parameters.Add("aaa",param1);
   cmd.Parameters.Add("bbb",param2); //參數對象還需要名字,但是和查詢語句中的參數名無關
   cmd.Parameters[0].Direction = ParameterDirection.Input;
   cmd.Parameters[1].Direction = ParameterDirection.Input;
   conn.Open();
   reader = cmd.ExecuteReader();
   while(reader.Read()){
    Console.WriteLine(reader[0].ToString());
   }
   reader.Close();
  }
  catch(Exception ex){
   Console.WriteLine(ex.Message);
  }
  finally{
   conn.Close();
  }
 }
}

編譯之後,執行結果如下圖:


四、執行存儲過程
使用Command對象訪問數據庫的存儲過程,需要指定CommandType屬性,這是一個CommandType枚舉類型,默認情況下CommandType表示CommandText命令爲SQL批處理,CommandType.StoredProcedure值指定執行的命令是存儲過程。類似於參數化查詢,存儲過程的參數也可以使用Parameters集合來設置,其中Parameter對象的Direction屬性用於指示參數是隻可輸入、只可輸出、雙向還是存儲過程返回值參數。
需要注意的是如果使用ExecuteReader返回存儲過程的結果集,那麼除非DataReader關閉,否則無法使用輸出參數。下面是一個例子:
存儲過程
---------------------------------------------
CREATE procedure myProTest (
 @orderID as int,
 @elyTitle as varchar(50) output
)
as
select @elyTitle=ely.Title from [Orders] o join [Employees] ely on ely.EmployeeID=o.EmployeeID where o.OrderID=@orderID
select * from [Orders] where OrderID=@orderID
return 1
---------------------------------------------

程序
---------------------------------------------
using System;
using System.Data;
using System.Data.SqlClient;
public class myDataAccess{
 public static void Main(){
  SqlConnection conn = new SqlConnection("Server=localhost;Database=Northwind;User ID=sa;PWD=sa");
  SqlCommand cmd = new SqlCommand("myProTest",conn);
  cmd.CommandType = CommandType.StoredProcedure;
  cmd.Parameters.Add("@orderID",10252);
  cmd.Parameters.Add("@elyTitle",SqlDbType.VarChar,50);
  cmd.Parameters.Add("@return",SqlDbType.Int);
  cmd.Parameters[0].Direction = ParameterDirection.Input;
  cmd.Parameters[1].Direction = ParameterDirection.Output;
  cmd.Parameters[2].Direction = ParameterDirection.ReturnValue;
  SqlDataReader reader;
  try{
   conn.Open();
   Console.WriteLine("execute reader...");
   reader = cmd.ExecuteReader();
   Console.WriteLine("@orderID = {0}",cmd.Parameters[0].Value);
   Console.WriteLine("@elyTitle = {0}",cmd.Parameters[1].Value);
   Console.WriteLine("Return = {0}",cmd.Parameters[2].Value);
   Console.WriteLine("reader close...");
   reader.Close();
   Console.WriteLine("@orderID = {0}",cmd.Parameters[0].Value);
   Console.WriteLine("@elyTitle = {0}",cmd.Parameters[1].Value);
   Console.WriteLine("Return = {0}",cmd.Parameters[2].Value);
   Console.WriteLine("execute none query...");
   cmd.ExecuteNonQuery();
   Console.WriteLine("@orderID = {0}",cmd.Parameters[0].Value);
   Console.WriteLine("@elyTitle = {0}",cmd.Parameters[1].Value);
   Console.WriteLine("Return = {0}",cmd.Parameters[2].Value);
  }
  catch(Exception ex){
   Console.WriteLine(ex.Message);
  }
  finally{
   conn.Close();
  }
 }
}

---------------------------------------------
編譯後執行結果如下:

和參數化查詢一樣,OleDb或者Odbc數據提供程序不支持存儲過程的命名參數,需要把參數按照從左到右的順序,匹配Parameters集合。

發佈了75 篇原創文章 · 獲贊 0 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章