# Tạo một đối tượng câu lệnh phù hợp với kiểu cơ sở dữ liệu mà bạn định sử dụng; tất cả các đối tượng câu lệnh đều hiện thực giao diện System.Data.IDbCommand.. Dưới đây là danh sách các
Trang 11.1 Thực thi câu lệnh SQL hoặc thủ tục tồn trữ
V Bạn cần thực thi một câu lệnh SQL hoặc một thủ tục tồn trữ trên một cơ sở dữ
liệu
# Tạo một đối tượng câu lệnh phù hợp với kiểu cơ sở dữ liệu mà bạn định sử dụng; tất cả các đối tượng câu lệnh đều hiện thực giao diện System.Data.IDbCommand Cấu hình đối tượng câu lệnh bằng cách thiết lập các thuộc tính CommandType và CommandText của nó Thực thi câu lệnh bằng một trong các phương thức ExecuteNonQuery, ExecuteReader, hay ExecuteScalar tùy thuộc vào kiểu câu lệnh và kết quả của nó
Giao diện IDbCommand mô tả một câu lệnh cơ sở dữ liệu, và mỗi data-provider chứa một hiện thực duy nhất Dưới đây là danh sách các hiện thực IDbCommand cho năm data-provider chuẩn:
• System.Data.Odbc.OdbcCommand
• System.Data.OleDb.OleDbCommand
• System.Data.OracleClient.OracleCommand
• System.Data.SqlServerCe.SqlCeCommand
• System.Data.SqlClient.SqlCommand
Để thực thi một câu lệnh dựa trên một cơ sở dữ liệu, bạn phải có một kết nối đang mở (đã được thảo luận trong mục 10.1) và một đối tượng câu lệnh đã được cấu hình phù hợp với kiểu cơ sở dữ liệu đang truy xuất Bạn có thể tạo đối tượng câu lệnh một cách trực tiếp bằng phương thức khởi dựng, nhưng cách đơn giản hơn là sử dụng phương thức CreateCommand của đối tượng kết nối Phương thức CreateCommand trả về một đối tượng câu lệnh (đúng kiểu data-provider) và cấu hình nó với các thông tin cơ sở được lấy
từ kết nối mà bạn đã sử dụng để tạo câu lệnh Trước khi thực thi câu lệnh, bạn phải cấu hình các thuộc tính được mô tả trong bảng 10.3
[
Bảng 10.3 Các thuộc tính thông dụng của đối tượng câu lệnh
Thuộc tính Mô tả
CommandText
Chuỗi chứa câu lệnh SQL hoặc tên của thủ tục tồn trữ
Nội dung của thuộc tính CommandText phải tương thích với giá trị bạn chỉ định trong thuộc tính CommandType
CommandTimeout Số nguyên (int) chỉ định số giây đợi câu lệnh trả về trước
khi hết thời gian và ngoại lệ xảy ra Mặc định là 30 giây
Trang 2CommandType
Một giá trị thuộc kiểu liệt kê System.Data.CommandType, chỉ định kiểu câu lệnh được mô tả bởi đối tượng câu lệnh Đối với hầu hết các data-provider, giá trị hợp lệ là StoredProcedure (khi bạn muốn thực thi một thủ tục tồn trữ), và Text (khi bạn
muốn thực thi một câu lệnh SQL dạng text) Nếu đang sử dụng OLE DB Data Provider, bạn có thể chỉ định
TableDirect khi muốn trả về toàn bộ nội dung của một
hoặc nhiều bảng; hãy tham khảo tài liệu NET
Framework SDK để biết thêm chi tiết Mặc định là Text
Connection
Đối tượng IDbConnection, cung cấp kết nối đến cơ sở dữ liệu mà bạn sẽ thực thi câu lệnh trên đó Nếu bạn tạo câu lệnh bằng phương thức IDbConnection.CreateCommand, thuộc tính này sẽ tự động được thiết lập thành đối tượng IDbConnection mà bạn đã tạo câu lệnh từ nó
Parameters
Đối tượng System.Data.IDataParameterCollection, chứa tập các thông số để thay thế vào câu lệnh (xem mục 10.4
để biết cách sử dụng thông số)
Transaction
Đối tượng System.Data.IDbTransaction, mô tả phiên giao dịch mà câu lệnh được đưa vào đó (xem tài liệu
.NET Framework SDK để biết thêm chi tiết về phiên giao
dịch)
Một khi bạn đã cấu hình đối tượng câu lệnh thì có nhiều cách để thực thi nó, tùy thuộc vào bản chất của câu lệnh, kiểu dữ liệu do câu lệnh trả về, và bạn muốn xử lý dữ liệu theo định dạng nào
Để thực thi một câu lệnh như INSERT, DELETE, hoặc CREATE TABLE (không trả
về dữ liệu trong cơ sở dữ liệu), bạn hãy gọi ExecuteNonQuery Đối với các câu lệnh
UPDATE, INSERT, và DELETE, phương thức ExecuteNonQuery trả về một số nguyên
cho biết số hàng bị tác động bởi câu lệnh Đối với các câu lệnh khác như CREATE
TABLE, ExecuteNonQuery trả về -1 Ví dụ dưới đây sử dụng UPDATE để chỉnh sửa
một bản ghi
public static void ExecuteNonQueryExample(IDbConnection con) {
// Tạo và cấu hình câu lệnh mới
IDbCommand com = con.CreateCommand();
com.CommandType = CommandType.Text;
Trang 3com.CommandText = "UPDATE Employees SET Title = 'Sales Director'" +
" WHERE EmployeeId = '5'";
// Thực thi câu lệnh và xử lý kết quả
int result = com.ExecuteNonQuery();
if (result == 1) {
Console.WriteLine("Employee title updated.");
} else {
Console.WriteLine("Employee title not updated.");
}
}
Để thực thi một câu lệnh trả về một tập kết quả như lệnh SELECT hoặc thủ tục tồn trữ,
bạn hãy sử dụng phương thức ExecuteReader Phương thức này trả về một đối tượng IDataReader (sẽ được thảo luận trong mục 10.5) mà qua nó bạn có thể truy xuất đến dữ
liệu kết quả Hầu hết các data-provider cũng cho phép bạn thực thi nhiều câu lệnh SQL
trong một lời gọi phương thức ExecuteReader; ví dụ trong mục 10.5 sẽ giải thích điều này và trình bày cách truy xuất mỗi tập kết quả
Đoạn mã dưới đây sử dụng phương thức ExecuteReader để thực thi thủ tục tồn trữ “Ten
Most Expensive Products” (mười sản phẩm đắt nhất) từ cơ sở dữ liệu Northwind và hiển
thị kết quả trong cửa sổ Console:
public static void ExecuteReaderExample(IDbConnection con) {
// Tạo và cấu hình câu lệnh mới
IDbCommand com = con.CreateCommand();
com.CommandType = CommandType.StoredProcedure;
com.CommandText = "Ten Most Expensive Products";
// Thực thi câu lệnh và xử lý kết quả
using (IDataReader reader = com.ExecuteReader()) {
Console.WriteLine("Price of the Ten Most Expensive Products.");
while (reader.Read()) {
// Hiển thị chi tiết về sản phẩm
Console.WriteLine(" {0} = {1}",
reader["TenMostExpensiveProducts"],
reader["UnitPrice"]);
Trang 4}
}
}
Nếu muốn thực thi một truy vấn, nhưng chỉ cần giá trị thuộc cột đầu tiên của hàng đầu tiên trong dữ liệu kết quả, bạn hãy sử dụng phương thức ExecuteScalar Giá trị trả về là một tham chiếu đối tượng và bạn cần ép nó về đúng kiểu Dưới đây là ví dụ:
public static void ExecuteScalarExample(IDbConnection con) {
// Tạo và cấu hình câu lệnh mới
IDbCommand com = con.CreateCommand();
com.CommandType = CommandType.Text;
com.CommandText = "SELECT COUNT(*) FROM Employees";
// Thực thi câu lệnh và ép kiểu kết quả
int result = (int)com.ExecuteScalar();
Console.WriteLine("Employee count = " + result);
}
# Các hiện thực IDbCommand trong Oracle và SQL Data Provider có hiện thực
các phương thức thực thi câu lệnh bổ sung Mục 10.6 sẽ mô tả cách sử dụng phương thức ExecuteXmlReader do lớp SqlCommand cung cấp Bạn hãy tham
khảo tài liệu NET Frameworks SDK để biết thêm chi tiết về các phương thức
bổ sung ExecuteOracleNonQuery và ExecuteOracleScalar do lớp OracleCommand cung cấp
1.2 Sử dụng thông số trong câu lệnh SQL hoặc thủ tục tồn trữ
V Bạn cần thiết lập các đối số của một thủ tục tồn trữ hoặc sử dụng các thông số
trong một câu lệnh SQL để cải thiện tính linh hoạt
# Tạo đối tượng thông số phù hợp với kiểu đối tượng câu lệnh mà bạn dự định thực thi; tất cả các đối tượng thông số đều hiện thực giao diện System.Data.IDataParameter Cấu hình kiểu dữ liệu, giá trị, và hướng của đối tượng thông số và thêm chúng vào tập hợp thông số của đối tượng câu lệnh bằng phương thức IDbCommand.Parameters.Add
Tất cả các đối tượng câu lệnh đều hỗ trợ việc sử dụng thông số, do đó bạn có thể thực hiện các công việc sau:
• Thiết lập các đối số của thủ tục tồn trữ
• Lấy các giá trị trả về từ thủ tục tồn trữ
Trang 5• Đổi các giá trị thành các câu lệnh text lúc thực thi
Giao diện IDataParameter mô tả một thông số và mỗi data-provider chứa một hiện thực duy nhất Dưới đây là danh sách các hiện thực IDataParameter cho năm data-provider chuẩn:
• System.Data.Odbc.OdbcParameter
• System.Data.OleDb.OleDbParameter
• System.Data.OracleClient.OracleParameter
• System.Data.SqlServerCe.SqlCeParameter
• System.Data.SqlClient.SqlParameter
Các thuộc tính của đối tượng thông số mô tả những thứ mà một đối tượng câu lệnh cần khi thực thi một câu lệnh dựa trên data-source Bảng 10.4 mô tả các thuộc tính thường được sử dụng khi cấu hình cho thông số
Bảng 10.4 Các thuộc tính của đối tượng thông số
Thuộc tính Mô tả
DbType
Giá trị thuộc kiểu liệt kê System.Data.DbType, chỉ định kiểu dữ liệu chứa trong thông số Các giá trị thường được
sử dụng là String, Int32, DateTime, và Currency
Direction
Giá trị thuộc kiểu liệt kê System.Data.ParameterDirection, cho biết hướng truyền dữ liệu cho thông số Các giá trị hợp lệ là Input, InputOutput, Output, và ReturnValue
IsNullable Giá trị bool, cho biết thông số có chấp nhận giá trị null hay không ParameterName Chuỗi chứa tên thông số
Value Đối tượng chứa giá trị của thông số
Để sử dụng thông số với một câu lệnh text, bạn phải cho biết vị trí cần thay thế giá trị
thông số bên trong câu lệnh ODBC, OLE DB, và SQL Server CE Data Provider hỗ trợ các thông số vị trí (positional parameter); vị trí của mỗi thông số được nhận biết bằng
dấu chấm hỏi (?) Ví dụ, câu lệnh dưới đây cho biết có hai vị trí cần được thay thế bằng các giá trị thông số:
UPDATE Employees SET Title = ? WHERE EmployeeId = ?
SQL Server và Oracle Data Provider hỗ trợ các thông số được đặt tên (named parameter), cho phép bạn chỉ định mỗi vị trí thông số bằng một tên với biểu tượng @
Trang 6đứng trước Dưới đây là câu lệnh tương đương như trên nhưng sử dụng thông số được đặt tên:
UPDATE Employees SET Title = @title WHERE EmployeeId = @id
Để chỉ định các giá trị thông số để thay thế vào một câu lệnh, bạn phải tạo các đối tượng thông số đúng kiểu và thêm chúng vào tập hợp thông số của đối tượng lệnh (có thể được truy xuất thông qua thuộc tính Parameters) Bạn có thể thêm các thông số được đặt tên theo thứ tự bất kỳ, nhưng bạn phải thêm các thông số vị trí theo đúng thứ tự mà chúng xuất hiện trong câu lệnh text Khi bạn thực thi câu lệnh, giá trị của mỗi thông số sẽ được thay thế vào trong chuỗi lệnh trước khi câu lệnh được thực thi dựa trên data-source Phương thức ParameterizedCommandExample được trình bày ở đây mô tả cách sử dụng
thông số trong lệnh UPDATE của SQL Server Các đối số của phương thức
ParameterizedCommandExample gồm một SqlConnection đang mở và hai chuỗi Giá trị
của hai chuỗi này được thay thế vào trong lệnh UPDATE bằng thông số Ví dụ sau đây
trình bày hai cách để tạo đối tượng thông số: phương thức IDbCommand.CreateParameter, và phương thức IDbCommand.Parameters Bạn cũng có thể tạo các đối tượng thông số bằng phương thức khởi dựng và cấu hình chúng bằng các đối số của phương thức khởi dựng hoặc thông qua việc thiết lập các thuộc tính của chúng public static void ParameterizedCommandExample(SqlConnection con,
string employeeID, string title) {
// Tạo và cấu hình một câu lệnh mới chứa 2 thông số được đặt tên
SqlCommand com = con.CreateCommand();
com.CommandType = CommandType.Text;
com.CommandText = "UPDATE Employees SET Title = @title" +
" WHERE EmployeeId = @id";
// Tạo đối tượng SqlParameter cho thông số title
SqlParameter p1 = com.CreateParameter();
p1.ParameterName = "@title";
p1.SqlDbType = SqlDbType.VarChar;
p1.Value = title;
com.Parameters.Add(p1);
// Sử dụng cú pháp tốc ký để thêm thông số id
com.Parameters.Add("@id",SqlDbType.Int).Value = employeeID;
// Thực thi câu lệnh và xử lý kết quả
int result = com.ExecuteNonQuery();
Trang 7
}
Khi sử dụng thông số để thực thi thủ tục tồn trữ, bạn phải cung cấp các đối tượng thông
số đáp ứng cho mỗi đối số do thủ tục tồn trữ yêu cầu—gồm cả đối số input và output Bạn phải thiết lập thuộc tính Direction của mỗi thông số như được mô tả trong bảng 10.4 (mặc định là Input) Nếu thủ tục tồn trữ có giá trị trả về, thông số giữ giá trị trả về (với thuộc tính Direction là ReturnValue) phải là thông số đầu tiên được thêm vào tập hợp thông số Ví dụ dưới đây sử dụng thông số để thực thi thủ tục tồn trữ:
public static void StoredProcedureExample(SqlConnection con,
string category, string year) {
// Tạo và cấu hình một câu lệnh mới
SqlCommand com = con.CreateCommand();
com.CommandType = CommandType.StoredProcedure;
com.CommandText = "SalesByCategory";
// Tạo đối tượng SqlParameter cho thông số category
com.Parameters.Add("@CategoryName",SqlDbType.NVarChar).Value
= category;
// Tạo đối tượng SqlParameter cho thông số year
com.Parameters.Add("@OrdYear",SqlDbType.NVarChar).Value = year;
// Thực thi câu lệnh và xử lý kết quả
using (IDataReader reader = com.ExecuteReader()) {
§
}
}
1.3 Xử lý kết quả của truy vấn SQL bằng data-reader
V Bạn cần xử lý dữ liệu chứa trong đối tượng System.Data.IDataReader (đối tượng này được trả về khi bạn thực thi phương thức IDbCommand.ExecuteReader—đã được thảo luận trong mục 10.3)
# Sử dụng các thành viên của đối tượng IDataReader để duyệt tuần tự các hàng trong tập kết quả và truy xuất các item dữ liệu chứa trong mỗi hàng
Giao diện IDataReader mô tả một data-reader, đây là một cơ chế chỉ-tiến, chỉ-đọc
(forward-only, read-only) để truy xuất kết quả của truy vấn SQL Mỗi data-provider chứa
một hiện thực IDataReader duy nhất Dưới đây là danh sách các hiện thực IDataReader cho năm data-provider chuẩn:
Trang 8• System.Data.Odbc.OdbcDataReader
• System.Data.OleDb.OleDbDataReader
• System.Data.OracleClient.OracleDataReader
• System.Data.SqlServerCe.SqlCeDataReader
• System.Data.SqlClient.SqlDataReader
Giao diện IDataReader thừa kế giao diện System.Data.IDataRecord Các giao diện này khai báo các chức năng truy xuất dữ liệu và cấu trúc của dữ liệu có trong tập kết quả Bảng 10.5 mô tả vài thành viên thông dụng của giao diện IDataReader và IDataRecord Ngoài các thành viên được liệt kê trong bảng 10.5, data-reader còn cung cấp một tập các phương thức thực hiện việc lấy dữ liệu đã được định kiểu từ hàng hiện tại Mỗi phương thức sau đây nhận vào một đối số nguyên cho biết chỉ số (đánh từ 0) của cột mà dữ liệu
sẽ được trả về từ cột này: GetBoolean, GetByte, GetBytes, GetChar, GetChars, GetDateTime, GetDecimal, GetDouble, GetFloat, GetGuid, GetInt16, GetInt32, GetInt64, GetString, GetValue, và GetValues