Tải bản đầy đủ (.docx) (39 trang)

Truy xuất cơ sở dữ liệu bằng ado

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (416.37 KB, 39 trang )

ADO.NET
1/.

Bài 01: ADO.NET

2/.

Bài 02: The SqlConnection Object

3/.

Bài 03: The SqlCommand Object

4/.

Bài 04: Reading Data with the SqlDataReader

5/.

Bài 05: Working with Disconnected Data - The DataSet and SqlDataAdapter

6/.

Bài 06: Adding Parameters to Commands

7/.

Bài 07: Using Stored Procedures


Bài 1: ADO.NET


1/. Giới thiệu:

ADO.Net là 1 thư viện hướng đối tượng, nó cho phép tương tác với các nguồn dữ liệu. Thông
thường, các nguồn dữ liệu là CSDL, các tập tin văn bản, bảng tính Excel, tập tin XML.
2/. Data Providers

Chúng ta biết rằng ADO.NET cho phép chúng ta tương tác với các loại dữ liệu khác nhau và các
loại cơ sở dữ liệu khác nhau. Tuy nhiên, đó không phải là một tập hợp các lớp học cho phép bạn
thực hiện điều này. Vì các nguồn dữ liệu khác nhau có các giao thức khác nhau, chúng ta cần một
cách để giao tiếp với các nguồn dữ liệu bằng cách sử dụng giao thức đúng Một số nguồn dữ liệu
lớn hơn sử dụng các giao thức ODBC, nhiều nguồn dữ liệu mới hơn sử dụng các giao thức OleDb,
và có những nguồn dữ liệu mà cho phép ta giao tiếp với chúng trực tiếp thông qua các thư viện lớp
.NET là ADO.NET.
ADO.NET cung cấp một cách tương đối phổ biến để tương tác với các nguồn dữ liệu, đi kèm
trong bộ khác nhau của thư viện đối với mỗi cách ta có thể làm việc /nói chuyện với một nguồn dữ
liệu. Các thư viện này được gọi là Data Providers. Bảng sau liệt kê một số Data Provider phổ biến,
các tiền tố API chúng sử dụng, và các loại nguồn dữ liệu cho phép ta tương tác với nó.

Provider Name
ODBC Data Provider
OleDb Data Provider
Oracle Data Provider
SQL Data Provider
Borland Data Provider

Một ví dụ có thể giúp ta hiểu được ý nghĩa của tiền tố API. Một trong những đối tượng ADO.NET
đầu tiên ta sẽ tìm hiểu về là đối tượng kết nối, cho phép ta thiết lập một kết nối đến một nguồn dữ
liệu. Nếu chúng ta đã sử dụng Data Provider OleDb để kết nối với một nguồn dữ liệu đó cho thấy
một giao diện OleDb, chúng ta sẽ sử dụng một đối tượng kết nối có tên là OleDbConnection.
Tương tự như vậy, các kết nối tên đối tượng sẽ được bắt đầu bằng ODBC hoặc Sql cho một đối

tượng OdbcConnection trên một nguồn dữ liệu ODBC hoặc một đối tượng SqlConnection trên
một cơ sở dữ liệu SQL Server, tương ứng. Vì chúng ta đang sử dụng MSDE trong hướng dẫn này
(một phiên bản thu nhỏ của SQL Server) tất cả các đối tượng API sẽ có tiền tố Sql. nghĩa
SqlConnection.


3/. Đối tượng ADO.NET:

ADO.NET bao gồm nhiều đối tượng, ta có thể sử dụng để làm việc với dữ liệu. Phần này giới
thiệu một số đối tượng chính mà ta sẽ sử dụng. Trong bài này, ta sẽ được tiếp xúc với nhiều đối
tượng ADO.NET trong các ví dụ cụ thể. Các đối tượng dưới đây là những cái ta cần phải nắm
vững. Tìm hiểu về nó sẽ cung cấp cho bạn một ý tưởng về mọi điều ta có thể làm gì với dữ liệu
khi sử dụng ADO.NET.
A/. The SqlConnection Object (đối tượng kết nối)
Để tương tác với một cơ sở dữ liệu, ta phải có một kết nối đến nó. Các kết nối giúp xác định máy
chủ cơ sở dữ liệu, tên cơ sở dữ liệu, tên người dùng, mật khẩu và các thông số khác được yêu cầu
để kết nối đến cơ sở dữ liệu. Một đối tượng kết nối được sử dụng bởi các đối tượng lệnh ( Command
Object) do đó nó sẽ biết được cơ sở dữ liệu để thực hiện các lệnh trên.
B/. The SqlCommand Object (đối tượng lệnh)
Quá trình tương tác với cơ sở dữ liệu có nghĩa là ta phải xác định các hành động mà ta muốn thực
hiện. Điều này được thực hiện với một đối tượng lệnh. Ta sử dụng một đối tượng lệnh để gửi các
lệnh SQL vào cơ sở dữ liệu. Một đối tượng lệnh sử dụng một đối tượng kết nối để tìm ra cơ sở dữ
liệu để giao tiếp với nó. Ta có thể sử dụng một đối tượng lệnh một mình, để thực thi một lệnh trực
tiếp, hoặc gán một tham chiếu đến một đối tượng lệnh cho một SqlDataAdapter, nó nắm giữ một
bộ các lệnh làm việc trên một nhóm các dữ liệu như mô tả dưới đây.
C/. The SqlDataReader Object (đối tượng đọc dữ liệu)
Nhiều hoạt động / thao tác dữ liệu đòi hỏi rằng ta chỉ nhận được một dòng dữ liệu để đọc. Các đối
tượng Data Reader cho phép ta có được những kết quả của một câu lệnh SELECT từ một đối
tượng lệnh. Xét về hiệu suất, các dữ liệu trả về từ một Data Reader là một luồng dữ liệu nhanh
chóng. Điều này có nghĩa rằng ta chỉ có thể lấy dữ liệu từ các luồng một cách tuần tự, điều này là

tốt cho tốc độ, nhưng nếu ta cần thao tác dữ liệu, thì một DataSet là một đối tượng tốt hơn để làm
việc với nó.
D/. The DataSet Object (đối tượng DataSet)
Đối tượng DataSet là đại diện trong bộ nhớ của dữ liệu. Chúng chứa nhiều đối tượng khác như
DataTable, có chứa các cột và các hàng, giống như bảng cơ sở dữ liệu thông thường. Ta có thể xác
định mối quan hệ giữa các bảng để tạo mối quan hệ cha-con. DataSet được thiết kế đặc biệt để
giúp quản lý dữ liệu trong bộ nhớ và hỗ trợ hoạt động ngắt kết nối vào dữ liệu, khi một kịch bản
như vậy rất có ý nghĩa quản lý. DataSet là một đối tượng được sử dụng bởi tất cả Data Provider,
đó là lý do tại sao nó không có một tiền tố cụ thể cung cấp dữ liệu.


E/. The SqlDataAdapter Object ()
Đôi khi với dữ liệu ta làm việc chủ yếu là chỉ đọc và ta ít khi cần phải thực hiện thay đổi đối với
các nguồn dữ liệu bên dưới. Một số tình huống cũng gọi là bộ đệm dữ liệu trong bộ nhớ để giảm
bớt số lượng các cuộc gọi cơ sở dữ liệu cho dữ liệu mà nó không thay đổi. Các Data Adapter (bộ
chuyển đổi dữ liệu) làm cho nó dễ dàng hơn và bằng cách giúp đỡ việc quản lý dữ liệu trong một
chế độ ngắt kết nối. Các Data Adapter điền vào một đối tượng DataSet khi đọc và ghi dữ liệu
trong một đợt duy nhất. Một Data Adapter có chứa một tham chiếu đến các đối tượng kết nối và
mở, đóng kết nối tự động khi đọc hoặc ghi với cơ sở dữ liệu. Ngoài ra, các Data Adapter chứa các
tham chiếu đối tượng lệnh cho SELECT, INSERT, UPDATE, và DELETE trên dữ liệu. Ta sẽ
định nghĩa một Data Adapter cho mỗi bảng trong một DataSet và nó sẽ quản lý tất cả các giao tiếp
với cơ sở dữ liệu.
4/. Tóm lược:

ADO.NET là công nghệ .NET để tương tác với nguồn dữ liệu. Ta có một vài Data Provider, cho
phép giao tiếp với các nguồn dữ liệu khác nhau, tùy thuộc vào các giao thức nó sử dụng. Bất kể,
Data Provider nào được sử dụng, ta sẽ sử dụng một bộ tương tự của các đối tượng tương tác với
một nguồn dữ liệu. Các đối tượng SqlConnection cho phép ta quản lý kết nối với một nguồn dữ
liệu. Đối tượng SqlCommand cho phép bạn nói chuyện với một nguồn dữ liệu và gửi lệnh đến nó.
Để có thể nhanh chóng đọc và truy cập vào dữ liệu ta sử dụng SqlDataReader. Nếu ta muốn làm

việc với các dữ liệu bị ngắt kết nối, sử dụng một DataSet và thực hiện việc đọc từ / ghi đến các
nguồn dữ liệu bằng SqlDataAdapter.


Bài 2: The SqlConnection Object
1/. Giới thiệu:

Điều đầu tiên ta cần phải làm gì khi tương tác với một cơ sở dữ liệu là tạo ra một kết nối. Các kết
nối nói chuyện với cho phần còn lại của mã ADO.NET của cơ sở dữ liệu. Nó quản lý tất cả các
logic mức thấp kết hợp với các giao thức cơ sở dữ liệu cụ thể. Điều này làm dễ hơn và nhanh
chóng cho các công việc trên các đối tượng kết nối, mở kết nối, và đóng kết nối khi công việc
hoàn thành.
A/. Tạo 1 SqlConnection Object
Một đối tượng SqlConnection, giống như bất kỳ đối tượng C # khác. Ta chỉ cần khai báo và khởi
tạo các SqlConnection tất cả cùng một lúc, như mẫu sau:
SqlConnection conn = new SqlConnection(
"Data Source=(local);Initial Catalog=Northwind;Integrated Security=SSPI");

Đối tượng SqlConnection khởi tạo ở trên sử dụng một phương thức constructor với một đối số
đơn kiểu chuỗi đối số này được gọi là một chuỗi kết nối. Bảng sau mô tả từng bộ phận của chuỗi
kết nối.

Connection String Paramete
Data Source
Initial Catalog
Integrated Security
User ID
Password

Vd: Tích hợp an toàn khi ta đang ở trên một máy tính duy nhất. Tuy nhiên, Ta thường sẽ muốn

chỉ định bảo mật dựa trên SQL Server ID của người dùng với thiết lập cấp phép đặc biệt cho các
ứng dụng mà bạn đang sử dụng. Sau đây cho thấy một chuỗi kết nối, sử dụng User ID và mật khẩu
thông số:
SqlConnection conn = new SqlConnection
("Data Source=DatabaseServer;Initial Catalog=Northwind;User
ID=YourUserID;Password=YourPassword");


Chú ý: các nguồn dữ liệu được thiết lập để DatabaseServer để chỉ ra rằng ta có thể xác định một
cơ sở dữ liệu nằm trên một máy tính khác, qua mạng LAN, hoặc qua Internet. Ngoài ra, User ID
và mật khẩu thay thế các thông số an toàn tích hợp.
B/. Sử dụng SqlConnection
Mục đích của việc tạo ra một đối tượng SqlConnection là Ta có thể kích hoạt mã ADO.NET khác
để làm việc với một cơ sở dữ liệu. Đối tượng ADO.NET khác, chẳng hạn như một SqlCommand
và một SqlDataAdapter cần 1 đối tượng kết nối như là một tham số. Chuỗi các hoạt động xảy ra
trong cuộc đời của một SqlConnection như sau:
1. Khởi tạo các SqlConnection.
2. Mở các kết nối.
3. Thông qua kết nối để làm việc với các đối tượng ADO.NET khác.
4. Thực hiện các hoạt động cơ sở dữ liệu với các đối tượng ADO.NET khác.
5. Đóng kết nối.
Chú ý:





DataSource là server name trong SQL Server
Catalog là tên cơ sở dữ liệu cần kết nối
User ID và password là tài khoản SQL Server.

Chú ý cách kết nối và các xem chuỗi kết nối trong VS.

2/. Tóm lược:
Đối tượng SqlConnection để mã ADO.NET khác biết cơ sở dữ liệu đã kết nối và làm thế nào để
kết nối những thứ khác. Các bước ta sử dụng để quản lý vòng đời của một kết nối được tạo ra, mở,
chuyển, sử dụng, và đóng. Hãy chắc chắn để đóng kết nối đúng khi ta đang thực hiện với nó để
đảm bảo bạn không có một rò rỉ tài nguyên kết nối.
.


Bài 3: The SqlCommand Object
1/. Giới thiệu:
Một đối tượng SqlCommand cho phép ta xác định những loại tương tác ta muốn thực hiện với một
cơ sở dữ liệu. Ví dụ, ta có thể làm chọn, thêm, sửa đổi và xóa trên dòng dữ liệu trong một bảng cơ
sở dữ liệu. Các đối tượng SqlCommand có thể được sử dụng để hỗ trợ các tình huống quản lý dữ
liệu bị ngắt kết nối, nhưng trong bài này Ta sẽ chỉ sử dụng các đối tượng SqlCommand một mình.
Một bài học sau này trên SqlDataAdapter sẽ giải thích làm thế nào để thực hiện một ứng dụng sử
dụng dữ liệu bị ngắt kết nối. Bài học này cũng sẽ cho bạn thấy làm thế nào để lấy một giá trị duy
nhất từ một cơ sở dữ liệu, chẳng hạn như số lượng các Record trong một bảng.
Tạo 1 đối tượng SqlCommand
Tương tự như các đối tượng C# khác, ta tạo 1 thể hiện đối tượng SqlCommand theo mẫu sau:
SqlCommand cmd = new SqlCommand("lệnh SQL", conn);
Vd:
SqlCommand cmd = new SqlCommand("select Hoten from SinhVien", conn);
2/. Querying Data
Khi sử dụng một lệnh select SQL, ta lấy một tập hợp dữ liệu để xem. Để thực hiện điều này với
một đối tượng SqlCommand, ta sẽ sử dụng các phương thức ExecuteReader, nó trả về một đối
tượng SqlDataReader. Chúng ta sẽ thảo luận về SqlDataReader trong một bài học sau.
Vd: dưới đây cho thấy làm thế nào để sử dụng các đối tượng SqlCommand để có được một đối
tượng SqlDataReader:

// 1. Khởi tạo 1 lệnh truy vấn theo kết nối conn
SqlCommand cmd = new SqlCommand("select CategoryName from Categories", conn);
// 2. Gọi Execute reader để nhận kết quả truy vấn
SqlDataReader rdr = cmd.ExecuteReader();


Ví dụ trên khởi tạo 1 đối tượng SqlCommand, thông qua chuỗi lệnh SQL và đối tượng kết nối.
Sau đó ta có được đối tượng Data Reader bằng cách gọi phương thức thi hành ExecuteReader của
đối tượng SqlCommand.
3/. Thêm dữ liệu (Inserting Data):
Để thêm dữ liệu vào một cơ sở dữ liệu, sử dụng phương thức ExecuteNonQuery của đối tượng
SqlCommand. Mẫu sau đây cho thấy làm thế nào để chèn dữ liệu vào một bảng cơ sở dữ liệu:
// Tạo lệnh Insert để thêm dữ liệu vào bảng Categories
string insertString = @" insert into Categories (CategoryName, Description)
values ('Miscellaneous', 'Whatever doesn''t fit elsewhere')";
// 1. Khởi tạo SqlCommand mới với connection conn
SqlCommand cmd = new SqlCommand(insertString, conn);
// 2. Gọi ExecuteNonQuery để gởi lệnh
cmd.ExecuteNonQuery();
Thay vì một chuỗi chữ như tham số đầu tiên của SqlCommand, ta có thể sử dụng biến
insertString. Biến insertString được khai báo ngay trước khai báo SqlCommand.
Chú ý hai dấu nháy ('') trong văn bản insertString cho từ "doesn''t". Đây là cách ta thoát khỏi các
dấu nháy đơn để có được chuỗi đúng.
Một quan sát về những lệnh insert là chúng ta xác định rõ ràng các cột CategoryName và
Description. Các bảng Categories có một trường tiểu học trọng tên là CategoryID. Chúng tôi rời
này ra khỏi danh sách bởi vì SQL Server sẽ thêm vào lĩnh vực này chính nó. cố gắng để thêm một
giá trị cho một trường tiểu học trọng, chẳng hạn như CategoryID, sẽ tạo ra một ngoại lệ.
4/. Updating Data
Phương thức ExecuteNonQuery cũng được sử dụng cho việc cập nhật dữ liệu. Mẫu sau đây cho
thấy làm thế nào để cập nhật dữ liệu:

// tạo lệnh Update
string updateString = @" update Categories set CategoryName = 'Other' where CategoryName =
'Miscellaneous'";


// 1. Khởi tạo SqlCommand mới với conn
SqlCommand cmd = new SqlCommand(updateString);
// 2. Đặt thuộc tính conn
cmd.Connection = conn;
// 3. Gọi ExecuteNonQuery để gởi lệnh
cmd.ExecuteNonQuery();
Ta đã được thực hiện lệnh insert, với hai tham số. Phương thức ExecuteNonQuery thực hiện các
lệnh cập nhật.
5/. Deleting Data
Ta cũng có thể xóa dữ liệu bằng cách sử dụng phương thức ExecuteNonQuery. Mẫu sau đây cho
thấy làm thế nào để xóa một Record của cơ sở dữ liệu:
// Tạo chuỗi lệnh Delete
string deleteString = @"delete from Categories where CategoryName = 'Other'";
// 1. Khởi tạo SqlCommand mới
SqlCommand cmd = new SqlCommand();
// 2. Đặt thuộc tính CommandText là chuỗi lệnh Delete
cmd.CommandText = deleteString;
// 3. Đặt thuộc tính conn
cmd.Connection = conn;
// 4. Gọi ExecuteNonQuery để gởi lệnh
cmd.ExecuteNonQuery();
Ví dụ này sử dụng SqlCommand không có tham số. Mặt khác, nó đặt thuộc tính CommandText và
kết nối của đối tượng SqlCommand.

6/. Nhận giá trị đơn từ truy vấn

Đôi khi tất cả các bạn cần từ một cơ sở dữ liệu chỉ là một giá trị duy nhất, nó có thể là một số,
tổng, trung bình, hoặc giá trị tổng hợp khác từ một tập hợp dữ liệu. Thực hiện một ExecuteReader


và tính toán kết quả trong mã của bạn không phải là cách hiệu quả nhất để làm điều này. Sự lựa
chọn tốt nhất là để cho các cơ sở dữ liệu thực hiện công việc và trở về chỉ là giá trị duy nhất mà
bạn cần. Mẫu sau đây cho thấy làm thế nào để làm điều này với phương thức ExecuteScalar:
// 1. Khởi tạo 1 SqlCommand mới
SqlCommand cmd = new SqlCommand("select count(*) from Categories", conn);
// 2. Gọi ExecuteNonQuery để gởi lệnh
int count = (int)cmd.ExecuteScalar();
Truy vấn trong SqlCommand có được số record từ bảng Categories. Truy vấn này sẽ chỉ trả lại
một giá trị duy nhất. Các phương pháp ExecuteScalar ở bước 2 trả về giá trị này. Từ kiểu trả về
của ExecuteScalar là loại đối tượng, chúng ta sử dụng một phép toán để chuyển đổi các giá trị int.
Vd: Gộp tất cả:
Để đơn giản, chúng ta cho thấy các đoạn mã trong phần trước để chứng minh các kỹ thuật được áp
dụng. Nó cũng rất hữu ích để có một danh sách toàn bộ mã để xem làm thế nào mã này được sử
dụng trong một chương trình.
Có Database BAITAP, Table ChuyenGia như sau:

using
using
using
using

System;
System.Collections.Generic;
System.Data;
System.Data.SqlClient;


class SqlCommandDemo
{
SqlConnection conn;
public SqlCommandDemo() //constructor của Class
{
// Khởi tạo connection
SqlConnection conn = new SqlConnection(@"server = .\SQLEXPRESS;database = BAITAP;integrated
security = true");
/*hoặc dùng:


SqlConnection conn = new SqlConnection(@"Data Source=XUANCUONG-PRO/SQLEXPRESS;Initial
Catalog=Baitap;Integrated Security=True");
*/
}

static void Main()
{
//khởi tạo biến scd
SqlCommandDemo scd = new SqlCommandDemo();
Console.WriteLine();
Console.WriteLine("Bang Chuyen gia truoc khi them");
Console.WriteLine("-------------------------------");
// gọi phương thức ExecuteReader
scd.ReadData();
// gọi phương thức ExecuteNonQuery để Insert
scd.Insertdata();
Console.WriteLine();
Console.WriteLine("Bang Chuyen gia sau khi them");
Console.WriteLine("-----------------------------");

scd.ReadData();
// gọi phương thức ExecuteNonQuery để Update
scd.UpdateData();
Console.WriteLine();
Console.WriteLine("Bang Chuyen gia truoc khi sua");
Console.WriteLine("------------------------------");
scd.ReadData();
// gọi phương thức ExecuteNonQuery để Delete
scd.DeleteData();
Console.WriteLine();
Console.WriteLine("Bang Chuyen gia sau khi xoa");
Console.WriteLine("----------------------------");
scd.ReadData();
// gọi phương thức ExecuteScalar để đếm số Record
int numberOfRecords = scd.GetNumberOfRecords();

}

Console.WriteLine();
Console.WriteLine("So mau tin: {0}", numberOfRecords);
Console.ReadKey();

public void ReadData()
// đọc và xuất dữ liệu ra cho xem
{
SqlConnection conn = new SqlConnection(@"server = .\SQLEXPRESS;database = BAITAP;integrated
security = true");


SqlDataReader rdr = null;

try
{

// mở connection
conn.Open();
// 1. khởi tạo command là 1 query và connection
SqlCommand cmd = new SqlCommand("select * from ChuyenGia", conn);
// 2. gọi phương thức ExecuteReader để nhận kết quả của query
rdr = cmd.ExecuteReader();
// Xuất ra Field 0, 1, 2 cho từng record
while (rdr.Read())
{
Console.WriteLine(rdr[0] + ", " + rdr[1] + ", " + rdr[2]);
}

}
finally
{
// đóng DataReader
if (rdr != null)
{
rdr.Close();
}

}

// đóng connection
if (conn != null)
{
conn.Close();

}

}

public void Insertdata() // dùng phương thức ExecuteNonQuery để Insert
{
try
{
// mở connection
SqlConnection conn = new SqlConnection(@"server = .\SQLEXPRESS;database = BAITAP;integrated
security = true");
conn.Open();
// tạo chuỗi Insert
string insertString = @"insert into ChuyenGia (MSCG, HOTEN, TUOI)
values ('C0006','Trần Văn Tý','35')";
// 1. khởi tạo 1 lệnh với query và connection
SqlCommand cmd = new SqlCommand(insertString, conn);
// 2. Call ExecuteNonQuery to send command
cmd.ExecuteNonQuery();

}
finally
{


// đóng connection
if (conn != null)
{
conn.Close();
}

}

}

public void UpdateData() // dùng phương thức ExecuteNonQuery để Update
{
try
{
// mở connection
SqlConnection conn = new SqlConnection(@"server = .\SQLEXPRESS;database = BAITAP;integrated
security = true");
conn.Open();
// tạo chuỗi lệnh update
string updateString = @"update ChuyenGia set HOTEN = 'Trần Văn Chuột'
where HOTEN = 'Trần Văn Tý'";
// 1. khởi tạo 1 command
SqlCommand cmd = new SqlCommand(updateString);
// 2. đặt thuộc tính Connection
cmd.Connection = conn;
// 3. gọi phương thức ExecuteNonQuery để gởi lệnh
cmd.ExecuteNonQuery();

}

}
finally
{
// đóng connection
if (conn != null)
{

conn.Close();
}
}

public void DeleteData() // use ExecuteNonQuery method for Delete
{
try
{
// mở connection
SqlConnection conn = new SqlConnection(@"server = .\SQLEXPRESS;database = BAITAP;integrated
security = true");
conn.Open();
// chuỗi lệnh xoá
string deleteString = @"delete from ChuyenGia
where MSCG = 'C0006'";
// 1. khởi tạo 1 command
SqlCommand cmd = new SqlCommand();
// 2. đặt thuộc tính CommandText
cmd.CommandText = deleteString;


// 3. đặt thuộc tính Connection
cmd.Connection = conn;
// 4. gọi phương thức ExecuteNonQuery để gởi lệnh
cmd.ExecuteNonQuery();

}
finally
{
// đóng connection

if (conn != null)
{
conn.Close();
}
}
}

public int GetNumberOfRecords()
{
int count = -1;

// use ExecuteScalar method

try
{
// mở connection
SqlConnection conn = new SqlConnection(@"server = .\SQLEXPRESS;database = BAITAP;integrated
security = true");
conn.Open();
// 1. khởi tạo 1 command
SqlCommand cmd = new SqlCommand("select count(*) from ChuyenGia", conn);
// 2. gọi phương thức ExecuteScalar để gởi lệnh
count = (int)cmd.ExecuteScalar();
}
finally
{
// đóng connection
if (conn != null)
{
conn.Close();

}
}
return count;
}

}

Trong chương trình, các đối tượng SqlConnection được khởi tạo trong Class SqlCommandDemo.
Điều này là không sao vì các đối tượng chính nó sẽ được làm sạch khi CLR (Commont Langue
Runtime) thu gom rác thực hiện. Điều quan trọng là chúng ta đóng kết nối mỗi khi gọi nó xong.
Chương trình này sẽ mở ra các kết nối trong một khối try và đóng nó trong một cuối cùng khối
trong mỗi phương pháp.


Phương thức ReadData hiển thị nội dung các cột của bảng ChuyenGia. Chúng ta sử dụng nó nhiều
lần trong các phương thức chính để hiển thị trạng thái hiện tại của bảng ChuyenGia, sau mỗi lần
thêm, cập nhật và xóa. Nó được thiết kế để thuận tiện để tái sử dụng nhiều lần.
7/. Tóm lược
Một đối tượng SqlCommand cho phép ta thực hiện truy vấn và gửi lệnh đến một cơ sở dữ liệu. Nó
có phương thức mà chuyên biệt cho các lệnh khác nhau.




Phương thức ExecuteReader trả về một đối tượng SqlDataReader để xem kết quả của một
truy vấn chọn.
Để chèn, cập nhật và xóa các lệnh SQL, bạn sử dụng phương thức ExecuteNonQuery.
Nếu bạn chỉ cần một tổng giá trị duy nhất từ một câu truy vấn, ExecuteScalar là sự lựa chọn
tốt nhất.



Bài 4: Đọc dữ liệuvới SqlDataReader
1/. Giới thiệu
Một SqlDataReader là một kiểu đó là tốt cho việc đọc dữ liệu một cách hiệu quả nhất có thể. Bạn
không thể sử dụng nó để ghi dữ liệu. SqlDataReaders thường được mô tả như luồng dữ liệu
nhanh.
Ta có thể đọc từ các đối tượng SqlDataReader một cách tuần tự theo hướng Forward only (chỉ đi
tới). Một khi ta đã đọc một số dữ liệu, ta có thể phải phải lưu nó bởi vì ta sẽ không thể quay trở lại
và đọc lại nó.

2/. Tạo đối tượng SqlDataReader
Nhận một thể hiện của một SqlDataReader có một chút khác biệt hơn so với cách làm của đối
tượng ADO.NET khác. Ta phải gọi ExecuteReader vào một đối tượng lệnh, như sau:
SqlDataReader rdr = cmd.ExecuteReader();
Phương thức ExecuteReader của đối tượng SqlCommand, cmd, trả về một thể hiện
SqlDataReader. Tạo một SqlDataReader với lệnh new không có tác dụng gì cả.
3/. Reading Data


Như ví dụ ở bài trước, SqlDataReader trả về dữ liệu qua một luồng liên tục. Để đọc dữ liệu, ta
phải lấy dữ liệu từ một bảng từng dòng một (row-by-row). Mỗi lần một dòng được đọc, dòng
trước đó sẽ không còn hiệu lực. Để đọc lại dòng đó, bạn cần phải tạo một thể hiện mới của
SqlDataReader và đọc xuyên qua luồng dữ liệu một lần nữa.
Phương pháp điển hình để đọc từ luồng dữ liệu trả về bởi SqlDataReader là lặp qua mỗi dòng với
một vòng lặp while. Đoạn code sau cho thấy cách làm điều này:
while (rdr.Read())
{
// get the results of each column
string mscg = (string)rdr["MSCG"];
string hoten = (string)rdr["HOTEN"];

string tuoi
= (string)rdr["TUOI"];
// print out the results
Console.Write("{0,-10}", mscg);
Console.Write("{0,-50}", hoten);
Console.Write("{0,3}", tuoi);
Console.WriteLine();
}

Lưu ý phương thức Read() của SqlDataReader, rdr, trong điều kiện của vòng lặp while trong đoạn
code trên có kiểu bool và trả về true đến khi nào vẫn còn dòng để đọc. Sau khi dòng cuối được
đọc trong luồng dữ liệu, Read() trả về false.
Trong bài trước, chúng ta lấy cột đầu tiên của dòng bằng cách dùng indexer của SqlDataReader,
ví dụ rdr[0]. Ta có thể lấy mỗi cột của dòng với indexer kiểu số, nhưng cách này rất khó đọc. Ví
dụ trên dùng indexer kiểu string, với chuỗi sử dụng là tên cột từ câu truy vân SQL. Indexer kiểu
string sẽ dễ đọc hơn và giúp mã nguồn dễ hiểu.
Bỏ qua kiểu tham số của indexer, một indexer của SqlDataReader sẽ trả về kiểu object. Đó là lý
do tại sao ví dụ trên phải chuyển kết quả về kiểu string. Mỗi lần giá trị được lấy ra, bạn có thể làm
bất kì điều gì bạn muốn với chúng, như in ra màn hình với các phương thức của lớp Console.
4/. Đóng SqlDataReader
Luôn nhớ đóng SqlDataReader, giống như ta cần phải đóng SqlConnection. Cho đoạn mã truy cập
dữ liệu vào trong khối try và đưa đưa lậnh đóng vào khối finally như sau:
try


{
// truy cập dữ liệu
}
finally
{

// 3. Đóng SqlDataReader
if (rdr != null)
{
rdr.Close();
}
// đóng connection
}

Đoạn mã trên sẽ kiểm tra SqlDataReader để chắc chắn rằng nó không phải là null. Sau khi biết nó
một trường hợp khác null thì đóng lại.
Vd: SqlDataReader
Có Database BAITAP, Table SinhVien như sau:

using System;
using System.Data;
using System.Data.SqlClient;
namespace Bai4
{
class ReaderDemo
{
static void Main()
{
ReaderDemo rd = new ReaderDemo();
rd.SimpleRead();
// gọi phương thức SimpleRead()
}
public void SimpleRead() //phương thức đọc dữ liệu
{
// khai báo SqlDataReader
SqlDataReader rdr = null;

// tạo đối tượng connection


SqlConnection conn = new SqlConnection(@"server = .\SQLEXPRESS;database = BAITAP;integrated
security = true");
// tạo command
SqlCommand cmd = new SqlCommand("select MSSV, HOTEN from SinhVien", conn);
try
{
// mở connection
conn.Open();
// 1. nhận 1 thể hiện của SqlDataReader
rdr = cmd.ExecuteReader();
// xuất tên Field / cột làm tiêu đề
Console.WriteLine("Ma so SV
Hoten
");
Console.WriteLine("--------------------------------");
// 2. xuất dữ liệu
while (rdr.Read())
{
// nhận dữ liệu từ các Field
string maso = (string)rdr["MSSV"];
string ten = (string)rdr["Hoten"];

// xuất nội dung
Console.Write("{0,-12}", maso);
Console.WriteLine("{0,-30}", ten);
}
}

finally
{
// 3. đóng SqlDataReader
if (rdr != null)
{
rdr.Close();
}
// đóng connection
if (conn != null)
{
conn.Close();
}
}
}

}

5/. Tóm lược

}


Đối tượng SqlDataReader cho phép ta chỉ đọc dữ liệu theo cách hướng tới. Ta truy xuất dữ liệu
bằng cách đọc từng dòng từ dòng. Gọi phương thức Close để đóng SqlDataReader nhằm đảm bảo
không có bất kỳ rò rỉ tài nguyên.


Bài 5: Disconnected Data - The DataSet và SqlDataAdapter
1/. Giới thiệu
Một DataSet là một đối tượng chứa dữ liệu trong bộ nhớ và nó có thể bao gồm nhiều bảng.

DataSet chỉ chứa dữ liệu chứ không tương tác với nguồn dữ liệu. Thay vào đó, SqlDataAdapter sẽ
được dùng để quản lý các kết nối với nguồn dữ liệu và cho chúng ta chế độ làm việc disconnected.
SqlDataAdapter mở một kết nối chỉ khi cần thiết và đóng nó ngay sau khi tác vụ được hoàn
thành. Ví dụ, SqlDataAdapter thực hiện các tác vụ sau, khi đổ dữ liệu vào DataSet:
1.
2.
3.

Mở kết nối
Đổ dữ liệu vào DataSet (Fill)
Đóng kết nối

và thực hiện các công việc sau, khi cập nhật dữ liệu nguồn với thay đổi của DataSet:
1.
2.
3.

Mở kết nối
Ghi thay đổi từ DataSet vào dữ liệu nguồn (Update)
Đóng kết nối

Giữa 2 thao tác Fill và Update, các kết nối với nguồn dữ liệu được đóng lại và ta có thể tự do ghi,
đọc dữ liệu với DataSet. Đây chính là cơ chế của mô hình làm việc với disconnected data. Từ đó
ứng dụng sẵn sàng kết nối khi cần thiết, ứng dụng trở nên dễ phát triển hơn.

Hai kịch bản minh họa cho lý do tại sao ta cần làm việc với disconnected data: người dùng làm
việc không cần kết nối mạng và giúp Web site dễ phát triển hơn. Hãy xem xét việc nhà kinh doanh
cần dữ liệu của khách hàng trong khi họ đi công tác. Khi bắt đầu ngày, họ sẽ cần đồng bộ dữ liệu



với database chính để lấy các thông tin cập nhật mới nhất. Trong suốt ngày hôm đó, họ sẽ thực
hiện các thay đổi trên dữ liệu khách hàng hiện tại, thêm khách hàng mới, và nhập các hóa đơn
mới. Điều này hợp lệ vì họ có nguồn dữ liệu khách hàng riêng và những người khác không thể
thay đổi trên cùng dòng dữ liệu. Vào cuối ngày, nhà kinh doanh cập nhật sẽ kết nối vào mạng và
cập nhật thay đổi cho tiến trình xử lý ban đêm.
Kịch bản khác là giúp Website dễ phát triển hơn.Với một SqlDataReader, Ta phải trở lại database
lấy dữ liệu mỗi khi xem một trang. Điều này yêu cầu một kết nối mới cho mỗi lần tải trang, nó sẽ
ảnh hưởng lớn đến hiệu suất khi số lượng người dùng tăng lên. Một cách để khắc phục điều này là
dùng DataSet, chỉ cần cập nhật một lần và lưu trong bộ nhớ tạm (cache). Mỗi yêu cầu tải trang sẽ
kiểm tra cache và nạp dữ liệu (từ database) nếu nó không tồn tại hoặc lấy dữ liệu ra khỏi cache và
hiển thị nó. Điều này giúp hạn chế truy xuất database và tăng hiệu suất cho ứng dụng.
Các trường hợp ngoại lệ cho kịch bản trên bao gồm các trường hợp bạn cần cập nhật dữ liệu. Bạn
phải quyết định, dựa trên cách dữ liệu sẽ được dùng và chiến lược của bạn. Dùng disconnected
data khi thông tin của bạn thường là read-only, nhưng hãy xem xét các giải pháp thay thế (như
dùng đối tượng SqlCommand để cập nhật tức thời) khi ta có yêu cầu một vài thứ linh hoạt hơn.
Cũng vậy, nếu số lượng dữ liệu quá lớn để lưu trong bộ nhớ, ta sẽ cần dùng SqlDataReader để đọc
dữ liệu.
2/. Tạo đối tượng DataSet
Không có gì đặc biệt khi tạo một DataSet. Ta chỉ cần tạo một thể hiện mới, giống như đối tượng
C# khác:
DataSet daCustomers = new DataSet();
Tạo xong, ta có một DataSet rỗng và cần một SqlDataAdapter để nạp dữ liệu cho nó.
Phương thức constructor của DataSet không yêu cầu tham số. Tuy nhiên có một overload chấp
nhận một chuỗi đại diện cho tên của DataSet, được dùng nếu bạn cần chuyển dữ liệu thành XML.

3/. Tạo một SqlDataAdapter
SqlDataAdapter chứa các lệnh SQL và đối tượng connection để đọc và ghi dữ liệu. Ta khởi tạo nó
với câu SQL select và đối tượng connection:
SqlDataAdapter daCustomers = new SqlDataAdapter(“select … from …”, conn);



SqlDataAdapter daCustomers = new SqlDataAdapter(“select CustomerID, CompanyName from
Customers”, conn);
Dòng mã trên tạo một đối tượng SqlDataAdapter, daCustomers. Câu lệnh SQL select xác định dữ
liệu nào sẽ được đọc vào DataSet. Đối tượng connection conn, phải được khởi tạo từ trước, nhưng
không được mở. Đó là công việc của SqlDataAdapter để mở và đóng connection khi phương thức
Fill() và Update() được gọi.

SqlDataAdapter chứa tất cả lệnh cần thiết để tương tác với dữ liệu nguồn. Dòng mã trên xác định
câu lệnh select, nhưng không có các lệnh insert, update và delete.
Có hai cách để thêm các lệnh insert, update, delete: thông qua các thuộc tính (property) của
SqlDataAdapter hoặc với một SqlCommandBuilder. Trong bài này, ta sẽ tìm hiểu thấy cách dễ
nhất để làm điều này với SqlCommandBuilder. Đây là cách để thêm các lệnh vào SqlDataAdapter
với SqlCommandBuilder.
SqlCommandBuilder cmdBldr = new SqlCommandBuilder(daCustomers);
Lưu ý: dòng mã trên khởi tạo một đối tượng SqlCommandBuilder với constructor cần một tham
số là SqlDataAdapter, daCustomers. Điều này giúp SqlCommandBuilder biết đối tượng
SqlDataAdapter nào để thêm các lệnh vào.


SqlCommandBuilder sẽ đọc câu SQL select (lấy từ SqlDataAdapter), từ đó suy ra các lệnh
insert, update và delete, sau đó gán các lệnh mới vào các property Insert, Update, Delete
của SqlDataAdapter tương ứng.



Tuy nhiên, SqlCommandBuilder có 1 hạn chế. Nó làm việc khi ta thực hiện làm một câu
lệnh select đơn giản trên một bảng. Tuy nhiên, khi bạn cần kết hợp hai hoặc nhiều bảng
hoặc thực thi một stored procedure, nó sẽ không làm việc.


3/. Đổ dữ liệu vào DataSet
Để đổ dữ liệu vào DataSet bạn cần dùng phương thức Fill() của SqlDataAdapter, như sau:
daCustomers.Fill(dsCustomers, “Customers”);


Phương thức Fill() trên lấy hai tham số: một DataSet và một tên bảng. DataSet phải được tạo
trước khi bạn đổ dữ liệu vào nó. Tham số thứ hai là tên của bảng sẽ được tạo trong DataSet.
Ta có thể đặt bất kỳ tên gì cho bảng. Thông thường, ta nên đặt tên bảng trùng với tên gốc của nó
trong database. Tuy nhiên, nếu câu select của SqlDataAdapter chứa một lệnh join, bạn sẽ cần phải
đặt một tên rõ ràng khác cho bảng.
Phương thức Fill() có thể overload chấp nhận một tham số là DataSet. Trong trường hợp này,
bảng được tạo sẽ có tên mặc định là “table1” cho bảng đầu tiên. Số này sẽ tăng dần (table2, tabl3,
…,tableN) cho mỗi bảng thêm vào DataSet nếu như tên bảng không được chỉ ra trong phương
thức Fill().
4/. Sử dụng DataSet
Một DataSet thường được gắn dữ liệu vào DataGrid của ASP.NET trong Windows Form. Đây là
một ví dụ sẽ gán DataSet cho một Windows forms DataGrid:
dgCustomers.DataSource = dsCustomers;
dgCustomers.DataMember = “Customers”;
Lệnh đầu tiên trong đoạn mã trên là gán DataSet cho thuộc tính (property) DataSource của
DataGrid có tên dgCustomers. Nó giúp DataGrid biết có dữ liệu được gắn vào, tuy nhiên ta sẽ
thấy một dấu ‘+’ trên GUI bởi vì DataSet có thể giữ nhiều bảng và DataGrid cho phép bạn mở
rộng ra để xem mỗi bảng trong đó. Để chỉ định bảng nào được dùng, ta gán thuộc tính
DataMember của DataGrid bằng tên của bảng. Trong ví dụ, chúng ta gán tên là Customers, là tên
trùng với tên trong tham số thử hai trong phương thức Fill() của SqlDataAdapter.

5/. Cập nhật thay đổi
Sau khi thay đổi được thực hiện trên dữ liệu, ta sẽ cần ghi lại vào database. Dòng mã sau cho thấy
cách dùng phương thức Update của SqlDataAdapter để cập nhật các thay đổi vào database.
daCustomers.Update(dsCustomers, “Customers”);

Phương thức Update() trên được gọi trên thể hiện của SqlDataAdapter có tham số đầu tiên là
chính đối tượng gọi phương thức.


Tham số thử hai của phương thức Update() chỉ ra bảng nào trong DataSet sẽ được cập nhật. Bảng
chứa một danh sách các dòng dữ liệu đã bị thay đổi và các property Insert, Update, Delete của
SqlDataAdapter chứa các lệnh SQL dùng để thực hiện thay đối database.
6/. Tóm lược
DataSet chứa nhiều bảng và có thể lưu trong bộ nhớ để tái sử dụng. SqlDataAdapter cho phép ta
đổ dữ liệu vào một DataSet và cập nhật thay đổi vào database.
Ta không cần quan tâm về việc mở và đóng SqlConnection bởi vì SqlDataAdapter tự động làm
việc đó.
Một SqlCommandBuilder tạo ra các câu lệnh insert, update, delete dựa trên câu select của
SqlDataAdapter. Dùng phương thức Fill() của SqlDataAdapter để đổ dữ liệu vào DataSet. Gọi
phương thức Update() của SqlDataAdapter để cập nhật thay đổi vào lại database.
Vd: sẽ thực hiện ở phần Windows Form


×