Tải bản đầy đủ (.pdf) (108 trang)

Lập trình với cơ sở dữ liệu

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 (1.97 MB, 108 trang )

<span class='text_page_counter'>(1)</span><div class='page_container' data-page=1>

<b>PHÙNG NAM THẮNG, TRẦN BÁ PHAN </b>


<b>Bài giảng </b>



<b>LẬP TRÌNH VỚI CƠ SỞ DỮ LIỆU </b>



</div>
<span class='text_page_counter'>(2)</span><div class='page_container' data-page=2></div>
<span class='text_page_counter'>(3)</span><div class='page_container' data-page=3>

<b>LỜI NÓI ĐẦU </b>


Trong các hệ thống thơng tin thì dữ liệu của hệ thống là thành phần có vai
trị quan trọng, hầu hết các dữ liệu này được lưu trữ trong các hệ quản trị cơ sở
<i>dữ liệu. Bài giảng Lập trình với cơ sở dữ liệu được thiết kế giúp sinh viên có </i>
khái niệm và kỹ năng cần thiết để lập trình ứng dụng với cơ sở dữ liệu, tổ chức
chương trình theo mơ hình nhiều lớp, làm việc với cơ sở dữ liệu XML và kỹ
thuật lập trình LINQ. Để minh họa các kỹ thuật lập trình ứng dụng với cơ sở dữ
liệu tài liệu này sử dụng ngôn ngữ lập trình mà đang được sử dụng khá phổ biến
hiện nay là C#. Nội dung bài giảng gồm chương sau:


<i>Chương 1 - Lập trình với cơ sở dữ liệu ADO.NET cung cấp kiến thức về </i>
Lập trình với cơ sở dữ liệu, quá trình phát triển lập trình với cơ sở dữ liệu, và
trọng tâm là giới thiệu về bộ thư viện hướng đối tượng ADO.NET của Microsoft
để lập trình ứng dụng bằng các ngôn ngữ lập trình được hỗ trợ bới .NET
Framework trong đó có các ngôn ngữ rất phổ biến như là C# và Visual
Basic.NET,...


<i>Chương 2 - Lập trình trong hệ quản trị cơ sở dữ liệu cung cấp kiến thức về </i>
hệ quản trị cơ sở dữ liệu, ngôn ngữ truy vấn có cấu trúc và đặc biệt là ngơn ngữ
lập trình trong hệ quản trị cơ sở dữ liệu (T-SQL), trọng tâm của chương này là
trình bày về xây dựng và sử dụng thủ tục lưu trữ (Store Procedure), hàm người
dùng (Function), và bẫy lỗi qua Trigger trong quá trình xây dựng ứng dụng.


<i>Chương 3 - Thiết kê ứng dụng theo mô hình nhiều lớp trình bày các kiến </i>


trúc thiết kế ứng dụng đang được sử dụng để thiết kế phần mềm trong thực tế để
đảm bảo hệ thống được thiết kế tối ưu, một trong những mơ hình lập trình phổ
biến là mơ hình 3 lớp (Three-Layer Model hay là 3 tiers) được trình bày qua bài
tốn cụ thể.


<i>Chương 4 - Làm việc với tệp tin XML cung cấp kiến thức căn bản và kỹ </i>
thuật làm việc với với tệp tin XML bằng C#, một trong những cách thức phổ
biến đang được sử dụng để chia sẻ dữ liệu giữa các hệ thống thông tin với nhau.


<i>Chương 5 - LINQ giới thiệu giải pháp hợp nhất cho việc truy vấn dữ liệu, tích </i>
hợp cách truy vấn theo cú pháp SQL vào ngơn ngữ lập trình (cụ thể như C# hay
Visual Basic.NET), sử dựng làm việc với các hệ quản trị cơ sở dữ liệu và XML.


Trong quá trình biên soạn bài giảng, chúng tôi không thể tránh khỏi
những thiếu sót và sai lầm, rất mong được sự đóng góp ý kiến của quý độc giả
để bài giảng được hoàn thiện hơn nữa.


Chúng tôi xin trân trọng cảm ơn!


</div>
<span class='text_page_counter'>(4)</span><div class='page_container' data-page=4></div>
<span class='text_page_counter'>(5)</span><div class='page_container' data-page=5>

<b>Chương 1 </b>


<b>LẬP TRÌNH CƠ SỞ DỮ LIỆU VỚI ADO.NET </b>
Mục tiêu chương 1 bao gồm:


<i>- Cung cấp kiến thức về Lập trình với cơ sở dữ liệu; </i>
<i>- Quá trình phát triển lập trình với cơ sở dữ liệu; </i>


<i>- Giới thiệu về bộ thư viện hướng đối tượng ADO.NET của Microsoft để </i>
<i>lập trình ứng dụng bằng các ngơn ngữ lập trình được hỗ trợ bởi .NET </i>
<i>Framework trong đó có các ngơn ngữ rất phổ biến như là C# và Visual </i>


<i>Basic.NET,... </i>


<b>1.1. Tổng quan về lập trình với cơ sở dữ liệu </b>


<i><b>1.1.1. Giới thiệu </b></i>


Trong các hệ thống thông tin, dữ liệu là thành phần đóng vai trị quan
trọng duy trì hoạt đơng của hệ thống và tổ chức sử dụng hệ thống thông tin, các
dữ liệu thường tạo lập, quản lý bởi các hệ quản trị cơ sở dữ liệu như: Microsoft
SQL SERVER, Oracle, MySQL, PostgresSQL, DB2 hay Access…


Phần mềm ứng dụng được hiểu là phần mềm cho phép người sử dụng có
thể tạo lập, lưu trữ và khai thác dữ liệu thông qua phần mềm ứng dụng đó để
thực hiện một nghiệp vụ chun mơn nào đó được xây dựng trong phần mềm.


Tùy thuộc vào thiết kế và “độ lớn” của hệ thống thông tin mà hệ quản trị
dữ liệu có thể được cài đặt và chạy trên cùng một máy với phần mềm ứng dụng
hoặc hệ quản trị cơ sở dữ liệu và
phần mềm ứng dụng được đặt
trên hai hay nhiều máy khác
nhau. Tuy nhiên, dù cài đặt trên
cùng máy hoặc nhiều máy khác
nhau thì cơ chế làm việc với cơ
sở dữ liệu từ phần mềm ứng dụng
là trong suốt giống nhau. Từ các
phần mềm ứng dụng sẽ thực hiện
các chức năng tạo lập dữ liệu,
truy vấn dữ liệu, cập nhật dữ liệu, bảo trì dữ liệu,…dựa trên yêu cầu thiết kế ứng
dụng cụ thể mà người thiết kế phần mềm ứng dụng lựa chọn các công nghệ truy
cập, thao tác và xử lý dữ liệu cho phù hợp để đảm bảo tối ưu đối với ứng dụng


và thỏa mãn các yêu cầu thực tiễn.


</div>
<span class='text_page_counter'>(6)</span><div class='page_container' data-page=6>

thuật, cơng nghệ nhằm xây dựng các chương trình ứng sử dụng các hệ cơ sở dữ
liệu để tổ chức lưu trữ dữ liệu của chương trình.


<i><b>1.1.2. Quá trình phát triển lập trình cơ sở dữ liệu </b></i>


<i>1.1.2.1. Các thư viện DBAPI (DataBase Application Programming Interface) </i>
Một trong những mơ hình đầu tiên để các lập trình viên làm việc với các
hệ quản trị cơ sử dữ liệu là sử dụng DBAPI đây là bộ thư viện giao diện lập trình
ứng dụng cơ sở dữ liệu, mỗi một hệ quản trị cơ sử dữ liệu sẽ cung cấp bộ thư
viện truy dữ liệu tương ứng.


<b>Hình 1.2. Truy cập dữ liệu thơng qua thư viện DBAPI </b>


Mơ hình này, thơng thường sẽ thiết kế ra được các ứng dụng có khả năng
tối ưu truy cập dữ liệu vì sử dụng trực tiếp các thư viện của các nhà phát triển hệ
quản trị cơ sở dữ liệu, tuy nhiên có một nhược điểm là khi thay đổi hệ quản trị
cơ sở dữ liệu thì phải viết lại phần truy cập cơ sở dữ liệu hoặc viết lại toàn bộ
ứng dụng.


Một điểm nữa là đối với các lập trình viên để sử dụng được các hệ quản
trị cơ sở dữ liệu thì phải nghiên cứu về các thư viện này, việc này đòi hỏi cần
phải đào tạo khi thay đổi công nghệ hay đơn giản là thay đổi hệ quản trị cơ sở
dữ liệu đối với các đơn vị phát triển ứng dụng.


<i>1.1.2.2. Lập trình cơ sở dữ liệu bằngODBC (Open DataBase Conectivity) </i>


</div>
<span class='text_page_counter'>(7)</span><div class='page_container' data-page=7>

<b>Hình 1.3. Sử dụng ODBC truy cập dữ liệu trong các hệ quản trị CSDL </b>



Với thư viện ODBC việc thiết kế các chương trình ứng dụng sẽ có khả
năng độc lập với các hệ quản trị cơ sở dữ liệu, các lập trình viên thay vì phải phụ
thuộc vào thư viện của từng hệ quản trị cơ sở dữ liệu thì chỉ cần làm việc với
ODBC để truy cập dữ liệu trong các hệ quản trị cơ sở dữ liệu. ODBC bản chất là
một lớp trung gian giữa chương trình ứng dụng và hệ quản trị cơ sở dữ liệu. Lớp
trung gian đó được gọi là một Database Driver (trình điều khiển cơ sở dữ liệu)
có nhiệm vụ chuyển đổi những câu truy vấn của chương trình ứng dụng thành
những lệnh mà hệ quản trị cơ sở dữ liệu hỗ trợ và có khả năng đáp lại những
lệnh đó.


<i>1.1.2.3. Lập trình cơ sở dữ liệu bằng OLEDB và ADO </i>


<b>Hình 1.4. Sử dụng ADO và OLEDB truy cập cơ sở dữ liệu </b>


<i><b>OLEDB (Object Linking and Embedding) là thư viện liên kết nhúng để </b></i>
làm việc với các nguồn dữ liệu cả hệ quản trị dữ liệu quan hệ và không quan hệ.
OLE DB được Microsoft thiết kế để thay thế cho ODBC như một phương thức
truy cập cơ sở dữ liệu.


</div>
<span class='text_page_counter'>(8)</span><div class='page_container' data-page=8>

<b>Hình 1.5. Mơ hình đối tượng ADO 2.0 </b>


Ví dụ đoạn mã nguồn sử dụng ADO viết bằng ASP truy cập dữ liệu:


<%


' ASP code
Dim ObjConn
Dim rs


Dim strConn



Set ObjConn = Server.CreateObject("ADODB.Connection")
strConn="Microsoft.Jet.OLEDB.4.0;Data Source=sample.mdb;"
ObjConn.Open strConn


Set rs = Server.CreateObject("ADODB.Recordset")
rs.ActiveConnection = ObjConn


rs.Open "SELECT * FROM tblSample", ObjConn, adOpenKeyset,
adLockPessimistic, adCmdText


%>


<i>1.1.2.4. Kết nối dữ liệu bằng JDBC (Java Database Connectivity) </i>


Đối với các lập trình viên Java, để truy xuất dữ liệu sử dụng giao diện lập
trình chuẩn JDBC.


<b>Hình 1.6. Sử dụng JDBC trong Java truy cập dữ liệu </b>


</div>
<span class='text_page_counter'>(9)</span><div class='page_container' data-page=9>

<b>Hình 1.7. Mơ hình JDBC </b>
Ví dụ sử dụng Java truy cập cơ sở dữ liệu mySQL.


import java.SQL.*;


publicclassFirstExample{


staticfinalString JDBC_DRIVER ="com.mySQL.jdbc.Driver";
staticfinalString DB_URL ="jdbc:mySQL://localhost/EMP";
staticfinalString USER ="username";



staticfinalString PASS ="password";
publicstaticvoid main(String[] args){
Connection conn =null;


Statement stmt =null;
try{


Class.forName("com.mySQL.jdbc.Driver");


System.out.println("Connecting to database...");


conn =DriverManager.getConnection(DB_URL,USER,PASS);
System.out.println("Creating statement...");


stmt = conn.createStatement();
String SQL;


SQL ="SELECT id, first, last, age FROM Employees";
ResultSet rs = stmt.executeQuery(SQL);


while(rs.next()){


int id = rs.getInt("id");
int age = rs.getInt("age");


String first = rs.getString("first");
Stringlast= rs.getString("last");
System.out.print("ID: "+ id);
System.out.print(", Age: "+ age);


System.out.print(", First: "+ first);
System.out.println(", Last: "+last);
}


</div>
<span class='text_page_counter'>(10)</span><div class='page_container' data-page=10>

stmt.close();
conn.close();


}catch(SQLException se){
se.printStackTrace();
}catch(Exception e){


e.printStackTrace();
}finally{


try{


if(stmt!=null)


stmt.close();
}catch(SQLException se2){
}


try{


if(conn!=null)


conn.close();
}catch(SQLException se){


se.printStackTrace();


}//end finally try


}//end try


System.out.println("Goodbye!");
}//end main


}//end FirstExample
<i>1.1.2.5. Thư viện lập trình ADO.NET </i>


<b>Hình 1.8. Truy cập dữ liệu bằng ADO.NET </b>


</div>
<span class='text_page_counter'>(11)</span><div class='page_container' data-page=11>

<b>1.2. Kiến trúc của ADO.NET </b>


<b>Hình 1.9. Kiến trúc ADO.NET </b>


ADO.NET (Active Data Objects) nó là một phần của .NET Framework để
truy cập cơ sở dữ liệu cho bất kỳ ứng dụng nào phát triển trên nền .NET Framework.
<b>Data source hỗ trợ trong ADO.NET rất đa dạng bao gồm dữ liệu trong </b>
các hệ quản trị cơ sở dữ liệu quan hệ như Microsoft SQL SERVER, Oracle,
Microsoft Access hay trong các tệp tin dữ liệu XML, Excel,…


<b>Data Provider là các lớp thư viện sử dụng để truy cập đến các nguồn dữ </b>
liệu, mỗi hệ nguồn dữ liệu sẽ có một thư viện để truy xuất, tuy nhiên trong
ADO.NET cung cấp một cách thức chung để tương tác với nguồn dữ liệu. Bảng
1 dưới đây liệt kê một số Data provider phổ biển:


<b>Bảng 1.1. Các Data Provider phổ biến </b>
<b>Tiền </b>



<b>tố </b> <b>Tên Provider </b> <b>Chức năng </b> <b>Không gian tên (Namespace) </b>
Sql .NET


Framework Data
Provider for
SQL SERVER


Dùng cho việc truy
cập đến hệ quản trị
cơ sở dữ liệu
Microsoft SQL
SERVER.


System.Data.SQLClient


OleDb .NET


Framework Data
Provider for
OLEDB


Truy cập đến các hệ
quản trị cơ sở dữ
liệu hỗ trợ giao diện
OLE DB.


System.Data.OleDb


Odbc .NET



Framework Data
Provider for
ODBC


Kết nối đến cơ sở
dữ liệu thông qua
giao diện ODBC.


System.Data.Odbc


Oracle .NET


Framework Data
Provider for
Oracle


Dùng truy cập đến
dữ liệu trong hệ
quản trị cơ sở dữ
liệu Oracle.


</div>
<span class='text_page_counter'>(12)</span><div class='page_container' data-page=12>

<b>Dataset là khái niệm mới được đưa vào trong ADO.NET nó là một cơ sở </b>
dữ liệu ảo trong bộ nhớ trong của máy tính, Dataset có thể chứa một hay nhiều
đối tượng dữ liệu dạng bảng (DataTable), cùng với khố chính, khóa ngoại, ràng
buộc và các thông tin liên quan đến các bảng.


ASP.NET, Windows Forms, Webservices,…là các ứng dụng được xây
dựng trong đó sử dụng ADO.NET để truy cập dữ liệu, như vậy, Dựa trên
ADO.NET thì lập trình ứng dụng thì thành phần truy cập dữ liệu giữa các kiểu
ứng dụng ASP.NET, Windows Forms, Webservices là giống nhau.



<b>ADO.NET hỗ trợ mô hình truy cập ngắt kết nối (Disconnected Data </b>
<b>Architecture). Với kiến trúc này, dữ liệu được nhận về từ cơ sở dữ liệu và được </b>
lưu trên vùng nhớ cache của máy người dùng và chỉ kết nối đến cơ sở dữ liệu
khi có u cầu cần thay đổi các dịng dữ liệu hay yêu cầu dữ liệu mới.


ADO.NET sử dụng XML để tương tác với cơ sở dữ liệu, nghĩa là dữ liệu
trong cơ sở dữ liệu được chuyển sang định dạng XML để thực hiện các thao tác
liên quan đến cơ sở dữ liệu như truy vấn, cập nhật…


Các thành phần chi tiết của ADO.NET được thể hiện qua hình sau:


<b>Hình 1.10. Các thành phần chi tiết của ADO.NET </b>


</div>
<span class='text_page_counter'>(13)</span><div class='page_container' data-page=13>

<b>- Connection: Tào và quản lý kết nối đến nguồn dữ liệu dữ liệu như SQL </b>
SERVER, Oracle, ODBC, OLEDB, và My SQL.


<b>- Command: Cho phép thực thi câu lệnh SQL hay thủ tục lưu trữ và trả về </b>
dữ liệu. Một đối tượng Command dùng một đối tượng Connection để xác định
nguồn dữ liệu.


<i><b>- DataReader: Là đối tượng sử dụng để lấy dữ liệu theo một thứ tự nhất </b></i>
định của một câu lệnh Select từ một đối tượng Command phục vụ cho mục đích
“chỉ đọc” như là dữ liệu để hiển thị trong chương trình ứng dụng


<i><b>- DataAdapter: Là đối tượng chứa một tham chiếu đến đối tượng </b></i>
Connection và mở/đóng kết nối tự động khi đọc và ghi dữ liệu vào nguồn dữ
liệu, nó đóng vai trị cầu nối giữa DataSet, DataTable với cơ sở dữ liệu vật lý,
<b>1.3. Làm việc với các đối tượng của ADO.NET </b>



<i><b>1.3.1. Đối tượng Connection </b></i>


<i>Đối tượng Connection dùng để thiết lập một kết nối giữa ứng dụng với cơ </i>
sở dữ liệu. Kết nối đến cơ sở dữ liệu là thao tao đầu tiên cần phải thực hiện trước
khi muốn truy vấn hay cập nhật dữ liệu (thêm, sửa, xóa).


Hai kiểu đối tượng kết nối thường sử dụng nhất là OleDbConnection và
SQLConnection. Để kết nối đến SQL SERVER, chúng ta có thể sử dụng .NET
Frame Data Provider for SQL SERVER thông qua đối tượng SQLConnection.
Khi thực hiện kết nối đến cơ sở dữ liệu Access, ta sẽ phải sử dụng .NET
Framework Data Provider for OLE DB thông qua đối tượng
OLEDBConnection. Bảng sau đây hiển thị các thuộc tính và phương thức hay sử
dụng nhất của một đối tượng kết nối:


<b>Bảng 1.2. Thuộc tính và phương thức của đối tượng Connection </b>
<b>Tên thuộc tính, </b>


<b>phương thức </b> <b>Mơ tả </b>


ConnectionString


<i>- Cung cấp thông tin như dữ liệu nguồn (Data Source), </i>
tên cơ sở dữ liệu… được sử dụng để thiết lập kết nối
đến một cơ sở dữ liệu


Open() - Mở một kết nối đến Data Source được khai báo tại
ConnectionString


Close() - Dùng để đóng kết nối với Data Source



State


- Được dùng để kiểm tra trạng thái của một kết nối. Giá
trị:


</div>
<span class='text_page_counter'>(14)</span><div class='page_container' data-page=14>

Ví dụ: Một chuỗi kết nối:


String Connectionstring = “Server=.\SQLEXPRESS;”+


+ “Database=myDataBase;”+


+“UserId=myUsername; Pasword=myPassword;”


Chuỗi kết nối này sẽ kết nối tới SQL SERVER Database. Tham số mà
Server chỉ định tới là SQLEXPRESS, tham số Database chỉ định cơ sở dữ liệu
mà ta muốn truy cập, trong trường hợp này là myDataBase. Cuối cùng, các tham
số UserId và Password chỉ định tên đăng nhập và mật khẩu của người dùng được
định nghĩa trên hệ quản trị cơ sở dữ liệu. Mỗi tham số (parameter) được gán một
giá trị (value) qua dấu =, các cặp parameter - value được phân cách nhau bởi dấu
chấm phẩy.


<i>1.3.1.1. Khai báo sử dụng khơng gian tên </i>


Như vừa trình bày ở trên, mỗi loại cơ sở dữ liệu sẽ sử dụng một không
gian tên tương ứng. Trong trường hợp làm việc với cơ sở dữ liệu SQL SERVER
thì khơng gian tên là System.Data.SQLClient. Cú pháp khai báo như sau:


using System.Data.SQLClient;
<i>1.3.1.2. Khai báo đối tượng </i>



Sau khi khai báo sử dụng không gian tên cho việc sử dụng cơ sở dữ liệu
SQLServer, để kết nối cơ sở dữ liệu cần khai báo biến đối tượng
SQLConnection có tên SQLConn như sau:


SQLConnection SQLConn;
<i>1.3.1.3. Khởi tạo đối tượng </i>


Để sử dụng được biến SQLConn đã khai báo ở trên, cần khởi tạo đối
tượng này với một trong hai cú pháp như sau:


SQLConn = new SQLConnection();


SQLConn = new SQLConnection(ConnectionString);


Trong đó, với khởi tạo new SQLConnection() thì ta cung cấp chuỗi kết
nối cơ sở dữ liệu thơng qua thuộc tính ConnectionString; Trường hợp muốn
truyền chuỗi kết nối thơng qua một tham số truyền vào thì sẽ sử dụng cú pháp
khai báo thứ 2.


<i>Lưu ý: Có thể vừa khai báo vừa khởi tạo đối tượng theo mẫu: </i>
SQLConnection SQLConn = new SQLConnection();


<i>Hoặc </i>


</div>
<span class='text_page_counter'>(15)</span><div class='page_container' data-page=15>

SQLConnection(ConnectionString);


<i>Tuy nhiên, cũng có thể khai báo sau đó mới khởi tạo đối tượng: </i>
SQLConnection SQLConn;


SQLConn = new SQLConnection(ConnectionString);



Ví dụ về chuỗi kết nối cơ sở dữ liệu:


SQLConn.ConnectionString = “Server=.\SQLXPRESS; Database =
DatabaseName ; Truesed Connection = True”


<i>1.3.1.4. Mở kết nối </i>


<i>Để mở kết nối cơ sở dữ liệu, ta dùng phương thức Open với cú pháp khai </i>
báo sau:


SQLConn.Open();


<i>1.3.1.5. Đóng kết nối cơ sở dữ liệu </i>


Sau khi kết nối cơ sở dữ liệu, nếu khơng có nhu cầu sử dụng chúng thì có
<i>thể đóng kết nối này lại thơng qua phương thức Close bằng cú pháp sau: </i>


SQLConn.Close();
<i>1.3.1.6. Giải phóng đối tượng </i>


Trong trường hợp khơng sử đụng đến đối tượng kết nối cơ sở dữ liệu nữa,
có thể dùng phương thức dispose để giải phóng bộ nhớ mà đối tượng này đang
nắm giữ, cú pháp như sau:


SQLConnection.Dispose();


<i>Lưu ý: Sau khi giải phóng đối tượng, nếu có nhu cầu sử dụng lại cần phải khai </i>
báo khởi tạo lại các đối tượng này.



<i><b>1.3.2. Đối tượng Command </b></i>


Đối tượng Command dùng để thực thi một câu lệnh SQL như UPDATE,
DELETE, INSERT, SELECT hoặc một thủ tục (store procedure). Tùy kiểu Data
provider bạn đang dùng để làm việc với cơ sở dữ liệu mà sử dụng các lớp để tạo
ra các đối tượng Command tương ứng. SQLCommand dùng để tạo ra đối tượng
Command để thực thi các câu lệnh SQL trên SQL SERVER.


</div>
<span class='text_page_counter'>(16)</span><div class='page_container' data-page=16>

<b>Bảng 1.3. Thuộc tính và phương thức của đối tượng Command </b>


<b>Tên </b> <b>Diễn giải </b>


<b>Thuộc tính </b>


CommandText Thuộc tính dùng để gán hoặc lấy về câu lệnh SQL sẽ
thực thi trên đối tượng Command


Connection Thuộc tính dùng để gán hoặc lấy về đối tượng
Connection mà đối tượng Command sử dụng.


CommandTimeout Thuộc tính gán hoặc lấy về thời gian chờ tối đa để thực
hiện câu lệnh SQL


CommandType Thuộc tính chỉ ra kiểu câu lệnh mà đối tượng Command
sẽ thực hiện. CommandType có thể là một câu lệnh
SQL hoặc một Store Procedured


<b>Phương thức </b>


ExecuteNonQuery() Phương thức dùng thực hiện các câu lệnh SQL không


trả về dữ liệu như: INSERT, DELETE, UPDATE. Nó
trả về số dòng được thực hiện.


ExecuteReader() Thực hiện câu lệnh SQL SELECT, trả về đối tượng
Reader để chứa kết quả trả về câu truy vấn SELECT
ExecuteScalar() Trả về một giá trị duy nhất, ví dụ: Số bản ghi trong một


bảng, tổng lương của nhân viên


ExecuteXMLReader() Đọc nội dung trong một tệp tin XML và trả về đối tượng
XMLReader


Để cập nhật cơ sở dữ liệu sử dụng các mệnh đề truy vấn SQL như
(INSERT, UPDATE, DELETE)


Sử dụng SQL.NET Data Provider như sau:


//SQLStr là câu lệnh INSERT\UPDATE\DELETE
//SQLconn = SQLConnection object


SQLCommand cmd = new SQLCommand(SQLStr, SQLconn);
cmd.Connection.Open();


int effRows = cmd.ExcuteNonQuery();


Sử dụng OLE DB .NET Data Provider như sau:


//SQLStr là câu lệnh INSERT\UPDATE\DELETE
//SQLconn = OleDbConnection object



OleDbCommand cmd = new OleDbCommand(SQLStr, SQLconn);
cmd.Connection.Open();


int effRows = cmd.ExecuteNonQuery();


</div>
<span class='text_page_counter'>(17)</span><div class='page_container' data-page=17>

Đoạn mã để cập nhật một bản ghi sử dụng SQL .NET Data Provider


//Tạo kết nối:


String ConnectionString = “Server=.\SQLEXPRESS;”+
+ “Database=QL_SinhVien; UserId=sa;
Pasword=sa;”;


SQLConnection conn = new SQLConnection(ConnectionString);
//Tạo đối tượng Command:


SQLCommand insertCmd = new SQLCommand(“INSERT into
STUDENTS values(‘1051070112’, N‘Hoàng Văn’, N‘Hồng’,
‘K57_107’);


//Mở kết nối:


insertCmd.Connection.Open();


MessageBox.Show(“Connection opened”); //---Hiển thị thông
báo


//Hiển thị câu insert:


MessageBox.Show(insertCmd.CommandText);


//Thực thi:


insertCmd.ExecuteNonQuery;


MessageBox.Show(“Data has been added!”); //---T.Báo
success.


//Đóng kết nối:


insertCmd.Connection.Close();


Đoạn mã thực hiện câu lệnh ExecuteScalar
//Lấy sản phẩm có số lượng nhiều nhất


String SQL = “SELECT Max(Point) FROM [Tbl_DiemHocPhan]
//Tạo đối tượng Command:


SQLCommand cmd = new SQLCommand(SQL,conn);
//Mở kết nối:


cmd.Connection.Open();


//Thực hiện câu lệnh và lấy giá trị trả về


int count = Convert.ToInt32(cmd.ExecuteScalar());
//Hiển thị kết quả:


MessageBox.Show(count.ToString());
//Đóng kết nối:



cmd.Connection.Close();


<i><b>1.3.3. Đối tượng DataReader </b></i>


Lớp đối tượng DataReader dùng để đọc dữ liệu một cách tuần tự các bản
ghi từ đầu đến cuối. DataReader chỉ đọc dữ liệu ra (read only) mà không cập
nhật ngược lại dữ liệu vào cơ sở dữ liệu, kết quả trả về một tập các bản ghi.


</div>
<span class='text_page_counter'>(18)</span><div class='page_container' data-page=18>

<b>Bảng 1.4. thuộc tính và phương thức của DataReader </b>


<b>Tên </b> <b>Diễn giải </b>


<b>Thuộc tính </b>


FieldCount Thuộc tính dùng để đếm số cột


HasRows Thuộc tính kiểm tra xem DataReader có chứa bản ghi nào
khơng


IsClosed Thuộc tính kiểm tra xem DataReader đang đóng hay mở
<b>Phương thức </b>


Close() Đóng DataReader
GetName() Lấy về tên cột
Read() Đọc một bản ghi


GetValue() Đọc giá trị trong cột theo định dạng kiểu dữ liệu
GetByte() Đọc giá trị trong cột theo kiểu byte


GetChar() Đọc giá trị theo kiểu ký tự



GetInt32() Đọc giá trị theo kiểu số nguyên 32bit
GetString() Đọc giá trị một cột theo kiểu chuỗi


Ví dụ: Lấy danh sách mã tỉnh, tên tỉnh từ bảng dữ liệu tbl_Tinh


static void GetData(SqlConnection connection)
{


using (connection)
{


SqlCommand command = new SqlCommand("SELECT MaTinh,
TenTinh FROM tblTinh;",connection);




connection.Open();


SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)


{


while (reader.Read())
{


Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
reader.GetString(1));



}
}
else
{


Console.WriteLine("Khong co du lieu.");
}


reader.Close();
}


</div>
<span class='text_page_counter'>(19)</span><div class='page_container' data-page=19>

Ví dụ: Đoạn mã nguồn để hiển thị số cột và tên các cột trong một DataReader


try{


String ConnStr = “Server=.\SQLEXPRESS;”+


+“Database=QL_SinhVien; UserId=sa; Pasword=sa;”;
SQLConnection Conn = new SQLConnection();


Conn.ConnectionString = ConnStr;
SQLCommand cmd = new SQLCommand();


cmd.CommandText = “select * from Tbl_SinhVien”;
cmd.Connection = Conn;


Conn.Open();


SQLDataReader DataRead = cmd.ExecuteReader();
MessageBox.Show(“Số cột:”+DataRead.FieldCount);


for(int i=0;i<DataRead.FieldCount;i++)


MessageBox.Show(“Cột thứ ”+i+“ là:
”+DataRead.GetName(i);
DataRead.Close();
Conn.Close();
}
Catch(SQLException ex)
{
MessageBox.Show(ex.Message);
}


Ví dụ: Sử dụng DataReader truy vấn dữ liệu từ 2 bảng dữ liệu


static void GetData2(SqlConnection connection)
{


using (connection)
{


SqlCommand command = new SqlCommand("SELECT MaTinh,
TenTinh FROM tblTinh;" + "SELECT MaSV, HoTen FROM


tblSinhVien", connection);


connection.Open();


</div>
<span class='text_page_counter'>(20)</span><div class='page_container' data-page=20>

<i><b>1.3.4. Đối tượng DataSet và DataAdapter </b></i>



<i>1.3.4.1. Đối tượng DataSet </i>


Trong mơ hình truy cập dữ liệu truyền thống, khi thao tác dữ liệu trong cơ
sở dữ liệu, giữa máy khách (máy cài đặt ứng dụng) và máy chủ cơ sở dữ liệu
luôn duy trì kết nối, do đó rất tốn tài ngun của máy.


ADO.NET hỗ trợ một mơ hình thao tác dữ liệu mới gọi là truy cập dữ liệu
ngắt kết nối (Disconnected Data Acess) thông qua đối tượng DataSet. Đối tượng
này sẽ đọc và lưu trữ dữ liệu trong vùng nhớ đệm (Cached Memory), sau đó kết
nối sẽ bị ngắt, dữ liệu trong vùng nhớ đệm sau khi thao tác xong, kết nối sẽ được
mở và dữ liệu trong DataSet được cập nhật trở lại cơ sở dữ liệu.


<b>Hình 1.11. Sử dụng DataAdapter để đọc dữ liệu từ nguồn dữ liệu </b>
<b>vào DataSet </b>


Dữ liệu lưu trong DataSet được tổ chức dưới dạng một tập các bảng. Mỗi
bảng trong DataSet được biểu diễn bởi một đối tượng DataTable, mỗi dòng
trong DataTable được biểu diễn bởi DataRow và mỗi cột được biểu diễn bởi
DataColumn.DataRelation để biểu diễn mối quan hệ giữa các DataTable, đối tượng
Constraint để thiết lập ràng buộc trên DataTable để đảm bảo tính tồn vẹn dữ liệu.


</div>
<span class='text_page_counter'>(21)</span><div class='page_container' data-page=21>

<b>Tạo DataSet </b>


DataSet ds = new DataSet();
Hoặc:


DataSet ds = new DataSet(“DataSet Name”);


Khi dùng cách đầu tiên thì mặc định DataSet có tên là NewDataSet, cách
2 đặt tên cho DataSet. Tên của DataSet có thể thay đổi bằng thuộc tính


DataSetName. Nếu khơng đặt tên cho các bảng trong DataSet nó sẽ lấy tên mặc
định là Table, Table1, Table2, Table3…


<b>Bảng 1.5. Thuộc tính và phương thức của DataSet </b>


<b>Tên </b> <b>Diễn giải </b>


<b>Thuộc tính </b>


DataSetName Đặt tên/Lấy về tên của DataSet


Tables Trả về tập Relations, cho phép duyệt từ bảng cha đến
bảng con


Relations Trả về tập Relations liên kết giữa các bảng, cho phép di
chuyển từ bảng cha đến bảng con.


<b>Phương thức </b>


AcceptChange() Thực hiện thay đổi dữ liệu trên DataSet


Clear() Xóa tất cả các dòng trong các DataTable của DataSet
ReadXML() Đọc dữ liệu từ file XML vào DataSet


WriteXML() Ghi dữ liệu XML từ DataSet


Đối tượng DataSet có thể đọc dữ liệu từ tệp XML. Được thực hiện bằng
cách sử dụng phương thức ReadXML. Phương thức này đọc file XML bao gồm
cả schema của file XML. Ví dụ:



DataSet dsetRead = new DataSet();
dsetRead.ReadXML(“abc.XML”);


<i>1.3.4.2. Đối tượng Dataadapter </i>


</div>
<span class='text_page_counter'>(22)</span><div class='page_container' data-page=22>

<b>Hình 1.13. Mơ hình Dataset và DataAdapter </b>
<i>Đối tượng DataAdapter dùng để thực hiện 2 chức năng: </i>


- Đọc dữ liệu từ Data Souce (cơ sở dữ liệu, tệp XML...) vào Dataset.
- Cập nhật dữ liệu từ Dataset vào cơ sở dữ liệu.


Với mỗi hệ quản trị cơ sở dữ liệu mà ta kết nối đến sẽ có các lớp
DataAdapter tương ứng:


- OleDbDataAdapter
- SQLDataAdapter
- OdbcDataAdapter
- OracleDataAdapter


<b>Khởi tạo một đối tượng DataAdapter </b>


Có 3 phương thức khởi để tạo đối tượng DataAdapter
Cách 1: Câu lệnh truy vấn và chuỗi kết nối là tham số


String SQL = "SELECT * FROM movies";


SQLDataAdapter da = new SQLDataAdapter(SQL, connStr);
<i>Cách 2: Gán đối tượng Command cho thuộc tính SelectCommand </i>


SQLDataAdapter da = new SQLDataAdapter();



SQLConnection conn = new SQLConnection(connStr);
da.SelectCommand = new SQLCommand(SQL,conn);
Cách 3: Đối số là câu lệnh SQL và đối tượng Connection


</div>
<span class='text_page_counter'>(23)</span><div class='page_container' data-page=23>

<b>Bảng 1.6. Thuộc tính và phương thức của DataAdapter </b>


<b>Tên </b> <b>Diễn giải </b>


<b>Thuộc tính </b>


AcceptChangesDuringFill


Được gán giá trị True/False. Thuộc tính này
được gọi mỗi khi có một dịng được thêm vào
DataTable.


AcceptChangesDuringUpdate Được gán giá trị True/False. Phương thức được
gọi mỗi khi bảng được cập nhật dữ liệu.


FillLoadOption


Khi load dữ liệu từ DataSoure vào DataTable, có
thể những bản ghi này đã tồn tại trong dataTable
rồi.Thuộc tính này quy định cách xử lý các tình
huống như:


PreserveChanges/ Upset/ OverwriteChanges


TableMapping Trả về một tập hợp ánh xạ trong cơ sở dữ liệu và


DataTable.


GetFillParameter Trả về các tham số thiết lập bởi user khi thực
hiện câu lệnh SELECT.


DeleteCommand Thiết lập câu lệnh SQL hoặc store-procedure để
xóa một bản ghi trong DataSet.


InsertCommand Thiết lập câu lệnh SQL hoặc store-procedure để
thêm một bản ghi trong DataSet.


SelectCommand Thiết lập câu lệnh SQL hoặc store-procedure để
truy vấn một bản ghi trong DataSet.


UpdateCommand Thiết lập câu lệnh SQL hoặc store-procedure để
sửa một bản ghi trong DataSet.


<b>Phương thức </b>


Fill() Tạo một DataTable và load dữ liệu từ
DataSource vào DataTable đó.


Update()


Phương thức này gọi câu lệnh INSERT,
UPDATE, DELETE để update dữ liệu cho
DataTable.


<b>Sự kiện </b>



RowUpdated() Sự kiện xảy ra khi một bản ghi đã được cập nhật
vào SQL SERVER.


</div>
<span class='text_page_counter'>(24)</span><div class='page_container' data-page=24>

Ví dụ: Đoạn mã sử dụng DataAdapter lấy dữ liệu và đổ vào DataSet


string queryString = "SELECT MaSV, HoTen FROM tblSV";
SqlDataAdapter adapter = new SqlDataAdapter(queryString,
connection);


DataSet sv = new DataSet();
adapter.Fill(sv, "SinhVien");


Ví dụ: Đoạn mã sử dụng DataSet lấy chứa dữ liệu từ nhiều DataAdapter.


SqlDataAdapter tinhAdapter = new SqlDataAdapter(
"SELECT * FROM tblTinh ", customerConnection);


OleDbDataAdapter sinhvienAdapter = new OleDbDataAdapter(
"SELECT * FROM tblSinhVien", orderConnection);


DataSet sinhvien = new DataSet();
custAdapter.Fill(sinhvien, "Tinh");
ordAdapter.Fill(sinhvien, "SinhVien");
DataRelation relation =


customerOrders.Relations.Add("SinhvienTinh",
sinhvien.Tables["Tinh"].Columns["tinhID"],


sinhvien.Tables["SinhVien"].Columns["TinhID"]);
foreach (DataRow pRow in sinhvien.Tables["SinhVien


"].Rows)


{


Console.WriteLine(pRow["TinhID"]);


foreach (DataRow cRow in pRow.GetChildRows(relation))
Console.WriteLine("\t" + cRow["SinhVienID"]);


}


Ví dụ: Sử dụng tham số khi lấy dữ liệu bằng DataAdapter.


public static SqlDataAdapter GetDatabyParameters(SqlConnection
connection)


{


SqlDataAdapter adapter = new SqlDataAdapter();
adapter.MissingSchemaAction =


MissingSchemaAction.AddWithKey;
// Tạo các câu lệnh.


adapter.SelectCommand = new SqlCommand(


"SELECT CustomerID, CompanyName FROM CUSTOMERS",
connection);


adapter.InsertCommand = new SqlCommand(



"INSERT INTO Customers (CustomerID, CompanyName) " +
"VALUES (@CustomerID, @CompanyName)", connection);
adapter.UpdateCommand = new SqlCommand(


</div>
<span class='text_page_counter'>(25)</span><div class='page_container' data-page=25>

CompanyName = @CompanyName " +


"WHERE CustomerID = @oldCustomerID", connection);
adapter.DeleteCommand = new SqlCommand(


"DELETE FROM Customers WHERE CustomerID = @CustomerID",
connection);


// tạo các tham số.


adapter.InsertCommand.Parameters.Add("@CustomerID",
SqlDbType.Char, 5, "CustomerID");


adapter.InsertCommand.Parameters.Add("@CompanyName",
SqlDbType.VarChar, 40, "CompanyName");


adapter.UpdateCommand.Parameters.Add("@CustomerID",
SqlDbType.Char, 5, "CustomerID");


adapter.UpdateCommand.Parameters.Add("@CompanyName",
SqlDbType.VarChar, 40, "CompanyName");


adapter.UpdateCommand.Parameters.Add("@oldCustomerID",
SqlDbType.Char, 5, "CustomerID").SourceVersion =
DataRowVersion.Original;



adapter.DeleteCommand.Parameters.Add("@CustomerID",
SqlDbType.Char, 5, "CustomerID").SourceVersion =
DataRowVersion.Original;


</div>
<span class='text_page_counter'>(26)</span><div class='page_container' data-page=26>

<b>TÀI LIỆU THAM KHẢO </b>


1. David Sceppa, Programing Microsoft ADO.NET 2.0 (Deverloper Reference)
(2005), 2nd edition


2. Phạm Hữu Khang, C# 2005 – Tập 5, quyển 4 – Đối tượng ADO.NET và
XML (2005), NXB Lao động – Xã hội.


3. Website:


<i><b>Câu hỏi và bài tập: </b></i>


1. Lập trình CSDL được phát triển như thế nào?
2. Trình bày về các thành phần chính của ADO.NET?


3. Để lập trình ứng dụng bằng ngơn ngữ C# truy cập dữ liệu trong hệ quản trị cơ
sở dữ liệu foxpro thì có thể sử dụng các thư viện lập trình nào?


4. Sử dụng C#, lập trình lấy danh sách sinh viên trong bảng sinh viên từ cơ sở
dữ liệu MS SQL Server 2008 bằng ADO.NET.


</div>
<span class='text_page_counter'>(27)</span><div class='page_container' data-page=27>

<b>Chương 2 </b>


<b>LẬP TRÌNH TRONG HỆ QUẢN TRỊ DỮ LIỆU </b>
<i>Chương này sẽ đề cập các nội dung sau: </i>



<i>- Giới thiệu về cơ sở dữ liệu; </i>


<i>- Ngơn ngữ truy vấn có cấu trúc SQL; </i>


<i>- Lập trình trong hệ quản trị dữ liệu thông qua ngôn ngữ T-SQL; </i>


<i>- Tạo và sử dụng thủ tục lưu trữ, hàm người dùng tự định nghĩa và bẫy lỗi </i>
<i>thông qua đối tượng Trigger trong cơ sở dữ liệu. </i>


<b>2.1. Tổng quan về hệ quản trị dữ liệu SQL SERVER </b>


<i><b>2.1.1. Giới thiệu hệ quản trị dữ liệu SQL SERVER </b></i>


Microsoft SQL SERVER là một hệ quản trị cơ sở dữ liệu quan hệ
(Relation Database Mannagement System – RDBMS), cung cấp cách tổ chức dữ
liệu bằng cách lưu chúng vào các bảng. Dữ liệu quan hệ được lưu trữ trong các
bảng và các quan hệ đó được định nghĩa giữa các bảng với nhau.


Người dùng truy cập dữ liệu trên Server thông qua ứng dụng. người quản
trị cơ sở dữ liệu (CSDL) truy cập vào Server trực tiếp để thực hiện các chức
năng cấu hình, quản trị và thực hiện thao tác bảo trì CSDL.


Ngồi ra, SQL SERVER là một CSDL có khả năng mở rộng, nghĩa là
chúng có thể lưu một lượng lớn dữ liệu và hỗ trợ tính năng cho phép nhiều
người dùng truy cập dữ liệu đồng thời.


Các phiên bản của SQL SERVER phổ biến hiện nay trên thị trường là
SQL SERVER 7.0, SQL SERVER 2000, SQL SERVER 2005, SQL SERVER
2008, SQL SERVER 2012, SQL SERVER 2014…



<i><b>2.1.2. Các thành phần chính của MS SQL SERVER </b></i>


<i>2.1.2.1. Thành phần Server </i>


<b>SQL SERVER Database bao gồm Database Engine, lõi dịch vụ cho việc </b>
lưu trữ, xử lý và bảo mật dữ liệu, sao lưu và đồng bộ (Replication), tìm kiếm
tồn văn (Full-Text Search), và các công cụ cho việc quản trị dữ liệu quan hệ
vào XML.


<b>Analysis Services bao gồm các công cụ cho việc tạo và quản lý tiến trình </b>
phân tích trực tuyến (online analytical processing – OLAP) và các ứng dụng
khai thác dữ liệu.


</div>
<span class='text_page_counter'>(28)</span><div class='page_container' data-page=28>

<b>Notification Services dịch vụ thông báo Notification Services là nền tảng </b>
cho sự phát triển và triển khai các ứng dụng tạo và gửi thơng báo. Notification
Services có thể gửi thông báo theo định thời đến hàng ngàn người đăng ký sử
dụng nhiều loại thiết bị khác nhau.


<b>Integration Services là một tập hợp các công cụ đồ họa và các đối tượng </b>
lập trình cho việc di chuyển, sao chép và chuyển đổi dữ liệu.


<i>2.1.2.2. Thành phần Client </i>


<b>Connectivity Components là các thành phần cho việc truyền thông giữa </b>
Clients và Services, và các thư viện mạng như DB-Library, ODBC, và OLE DB.
<i><b>2.1.3. Các đối tượng trong MS SQL SERVER </b></i>


MS SQL SERVER gồm có các đối tượng sau:
- Cơ sở dữ liệu – Database;



- Bảng – Table;


- Khung nhìn – View;
- Chỉ mục – Index;
- Lược đồ - DiagraMS.
<i>2.1.3.1. Cơ sở dữ liệu - Database </i>


<b>Các Database hệ thống </b>


Khi cài đặt, SQL SERVER có 4 Database hệ thống được cài đặt, bao gồm:
<i><b>- Master: Ghi nhận thông tin cấp hệ thống, thông tin khởi tạo SQL </b></i>
SERVER và thiết lập cấu hình SQL SERVER. Database này cũng ghi nhận tất
cả các tài khoản đăng nhập, sự tồn tại của các Database khác, vị trí tập tin chính
cho tất cả Database người dùng.


<i><b>- Tempdb: Giữ các bảng tạm, các stored procedure tạm… được dùng cho </b></i>
các nhu cầu lưu trữ tạm của SQL SERVER.


<i><b>- Model: Là khuôn mẫu cho tất cả các cơ sở dữ liệu khác được tạo trên </b></i>
hệ thống kể cả tempdb. Database model phải được tồn tại trên hệ thống bởi vì nó
được đùng để tạo lại tempd mỗi khi SQL SERVER được khởi động.


<i><b>- MSdb: Giữ các bảng mà SQL SERVER Agent dùng để lập thời gian </b></i>
biểu thực thi các công việc, các cảnh bảo và các operator.


<b>Các database do người dùng tạo lập </b>


SQL SERVER 2005 cung cấp 2 cách tạo và xóa một Database sử dụng
các công cụ sau:



</div>
<span class='text_page_counter'>(29)</span><div class='page_container' data-page=29>

<i>2.1.3.2. Bảng – Table </i>


Dữ liệu bên trong một CSDL được tổ chức thành các bảng. Bên trong các
bảng, dữ liệu được tổ chức dưới dạng các dòng và các cột. mỗi dòng biểu diễn
một bản ghi duy nhất và mỗi cột biểu diễn cho một trường.


Khi tạo và làm việc với các bảng dữ liệu ta cần chú ý đến các thuộc tính
khác trên bảng như: kiểu dữ liệu, các ràng buộc, khóa, các quy tắc… các thuộc
tính này được sử dụng nhằm tạo ra các ràng buộc toàn vẹn trên các cột (trường),
trên bảng cũng như tạo ra các toàn vẹn tham chiếu giữa các bảng dữ liệu trong
CSDL.


<i>2.1.3.3. Khung nhìn - View </i>


Một khung nhìn có thể coi như một bảng “ảo” có nội dung được xác định
từ một truy vấn. Một truy vấn (query) là một tập hợp chỉ dẫn bằng câu lệnh SQL
nhằm truy xuát và hiển thị dữ liệu từ các bảng trong CSDL.


Một khung nhìn giống như một bảng với một tập các tên cột và các dòng
dữ liệu. Tuy nhiên, khung nhìn khơng tồn tại như một cấu trúc lưu trữ dữ liệu
trong CSDL. Dữ liệu bên trong khung nhìn thực chất là dữ liệu được xác định từ
một hay nhiều bảng cơ sở và do đó nó phụ thuộc vào các bảng cơ sở.


Các khung nhìn được dùng trong CSDL nhằm các mục đích sau:


 Tập trung trên dữ liệu được xác định;


 Đơn giản hóa thao tác dữ liệu;



 Tùy biến dữ liệu;


 Xuất khẩu (export) dữ liệu ;


 Bảo mật dữ liệu.
<i>2.1.3.4. Chỉ mục - Index </i>


Các chỉ mục được sử dụng nhằm hỗ trợ việc truy cập đến các dịng dữ liệu
được nhanh chóng dựa trên các giá trị của một hay nhiều cột. Chỉ mục được chia
ra làm 2 loại: Chỉ mục tụ nhóm (clustered index) và chỉ mục không tụ nhóm
(nonclutered index).


Một chỉ mục tụ nhóm là một chỉ mục mà trong đó thứ tự logic của các
khóa tương ứng thứ tự vật lý của các dòng tương ứng tồn tại trong bảng. Một
bảng chỉ có thể có tối đa một chỉ mục tụ nhóm.


</div>
<span class='text_page_counter'>(30)</span><div class='page_container' data-page=30>

<b>2.2. Tổng quan về lập trình trong hệ quản trị dữ liệu </b>


<i><b>2.2.1. Ngơn ngữ truy vấn có cấu trúc (SQL) </b></i>


Ngơn ngữ truy vấn có cấu trúc (Structure Query Language - SQL) và các
hệ quản trị cơ sở dữ liệu quan hệ là một trong những nền tảng kỹ thuật quan
trọng trong cơng nghiệp máy tính. Cho đến nay, có thể nói rằng SQL đã được
xem là ngôn ngữ chuẩn trong cơ sở dữ liệu. Các hệ quản trị cơ sở dữ liệu quan
hệ thương mại hiện có như Oracle, SQL SERVER, Informix, DB2,... đều chọn
SQL làm ngơn ngữ cho sản phẩm của mình.


Vậy thực sự SQL là gì? Tại sao nó lại quan trọng trong các hệ quản trị cơ
sở dữ liệu? SQL có thể làm được những gì và như thế nào? Nó được sử dụng ra
sao trong các hệ quản trị cơ sở dữ liệu quan hệ? Nội dung của chương này sẽ


cung cấp cho chúng ta cái nhìn tổng quan về SQL và một số vấn đề liên quan.


Tên gọi ngơn ngữ truy vấn có cấu trúc phần nào làm chúng ta liên tưởng
đến một công cụ (ngôn ngữ) dùng để truy xuất dữ liệu trong các cơ sở dữ liệu.
Thực sự mà nói, khả năng của SQL vượt xa so với một công cụ truy xuất dữ
liệu, mặc dù đây là mục đích ban đầu khi SQL được xây dựng nên và truy xuất
dữ liệu vẫn còn là một trong những chức năng quan trọng của nó. SQL được sử
dụng để điều khiển tất cả các chức năng mà một hệ quản trị cơ sở dữ liệu cung
cấp cho người dùng bao gồm:


 <b>Định nghĩa dữ liệu: SQL cung cấp khả năng định nghĩa các cơ sở dữ </b>


liệu, các cấu trúc lưu trữ và tổ chức dữ liệu cũng như mối quan hệ giữa các
thành phần dữ liệu.


<b> Truy xuất và thao tác dữ liệu: Với SQL, người dùng có thể dễ dàng </b>
thực hiện các thao tác truy xuất, bổ sung, cập nhật và loại bỏ dữ liệu trong các
cơ sở dữ liệu.


 <b>Điều khiển truy cập: SQL có thể được sử dụng để cấp phát và kiểm </b>


soát các thao tác của người sử dụng trên dữ liệu, đảm bảo sự an toàn cho cơ sở dữ liệu.


 <b>Đảm bảo toàn vẹn dữ liệu: SQL định nghĩa các ràng buộc toàn vẹn </b>
trong cơ sở dữ liệu nhờ đó đảm bảo tính hợp lệ và chính xác của dữ liệu trước
các thao tác cập nhật cũng như các lỗi của hệ thống.


</div>
<span class='text_page_counter'>(31)</span><div class='page_container' data-page=31>

Khác với các ngơn ngữ lập trình quen thuộc như C, C++, Java,... SQL là
ngơn ngữ có tính khai báo. Với SQL, người dùng chỉ cần mô tả các yêu cầu cần
phải thực hiện trên cơ sở dữ liệu mà không cần phải chỉ ra cách thức thực hiện các


u cầu như thế nào. Chính vì vậy, SQL là ngôn ngữ dễ tiếp cận và dễ sử dụng.


Bản thân SQL không phải là một hệ quản trị cơ sở dữ liệu, nó khơng thể
tồn tại độc lập. SQL thực sự là một phần của hệ quản trị cơ sở dữ liệu, nó xuất
hiện trong các hệ quản trị cơ sở dữ liệu với vai trò ngôn ngữ và là công cụ giao
tiếp giữa người sử dụng và hệ quản trị cơ sở dữ liệu.


Trong hầu hết các hệ quản trị cơ sở dữ liệu quan hệ, SQL có những vai trị
như sau:


<b> SQL là ngôn ngữ hỏi có tính tương tác: Người sử dụng có thể dễ </b>
dàng thơng qua các trình tiện ích để gởi các yêu cầu dưới dạng các câu lệnh SQL
đến cơ sở dữ liệu và nhận kết quả trả về từ cơ sở dữ liệu.


<b> SQL là ngơn ngữ lập trình cơ sở dữ liệu: Các lập trình viên có thể </b>
nhúng các câu lệnh SQL vào trong các ngơn ngữ lập trình để xây dựng nên các
chương trình ứng dụng giao tiếp với cơ sở dữ liệu.


<b> SQL là ngôn ngữ quản trị cơ sở dữ liệu: Thông qua SQL, người quản </b>
trị cơ sở dữ liệu có thể quản lý được cơ sở dữ liệu, định nghĩa các cấu trúc lưu
trữ dữ liệu, điều khiển truy cập cơ sở dữ liệu,...


<b> SQL là ngôn ngữ cho các hệ thống khách/chủ (client/server): Trong </b>
các hệ thống cơ sở dữ liệu khách/chủ, SQL được sử dụng như là công cụ để giao
tiếp giữa các trình ứng dụng phía máy khách với máy chủ cơ sở dữ liệu.


<b> SQL là ngôn ngữ truy cập dữ liệu trên Internet: Cho đến nay, hầu </b>
hết các máy chủ Web cũng như các máy chủ trên Internet sử dụng SQL với vai
trị là ngơn ngữ để tương tác với dữ liệu trong các cơ sở dữ liệu.



<b> SQL là ngôn ngữ cơ sở dữ liệu phân tán: Đối với các hệ quản trị cơ </b>
sở dữ liệu phân tán, mỗi một hệ thống sử dụng SQL để giao tiếp với các hệ
thống khác trên mạng, gởi và nhận các yêu cầu truy xuất dữ liệu với nhau.


<b> SQL là ngôn ngữ sử dụng cho các cổng giao tiếp cơ sở dữ liệu: </b>
Trong một hệ thống mạng máy tính với nhiều hệ quản trị cơ sở dữ liệu khác
nhau, SQL thường được sử dụng như là một chuẩn ngôn ngữ để giao tiếp giữa
các hệ quản trị cơ sở dữ liệu.


<i><b>2.2.2. Một số câu lệnh SQL thường dùng </b></i>


</div>
<span class='text_page_counter'>(32)</span><div class='page_container' data-page=32>

nhưng mỗi một hệ quản trị cơ sở dữ liệu có thể có một số thay đổi nào đó. Vì vậy,
đơi khi cú pháp chi tiết của các câu lệnh có thể sẽ khác nhau trong các hệ quản trị
cơ sở dữ liệu khác nhau. Dưới đây là một số cau lệnh thường được sử dụng:


<b>Bảng 2.1. Các câu lệnh SQL thường dùng </b>


<b>STT </b> <b>CÂU LỆNH </b> <b>CHỨC NĂNG </b>


<b>I. </b> <b>Thao tác dữ liệu </b>


1 SELECT Truy xuất dữ liệu


2 INSERT Bổ sung dữ liệu


3 UPDATE Cập nhật dữ liệu


4 DELETE Xóa dữ liệu


5 TRUNCATE Xóa tồn bộ dữ liệu trong bảng



<b>II. </b> <b>Định nghĩa dữ liệu </b>


1 CREATE TABLE Tạo bảng


2 ALTER TABLE Sửa đổi bảng


3 DROP TABLE Xóa bảng


4 CREATE VIEW Tạo khung nhìn


5 ALTER VIEW Sửa khung nhìn


6 DROP VIEW Xóa khung nhìn


7 CREATE INDEX Tạo chỉ mục


8 DROP INDEX Xóa chỉ mục


9 CREATE SCHEMA Tạo lược đồ cơ sở dữ liệu
10 DROP SCHEMA Xóa lược đồ cơ sở dữ liệu
11 CREATE PROCEDURE Tạo thủ tục lưu trữ


12 ALTER PROCEDURE Sửa đổi thủ tục lưu trữ
13 DROP PROCEDURE Xóa thủ tục lưu trữ


14 CREATE FUNCTION Tạo hàm (người dùng định nghĩa)
15 ALTER FUNCTION Sửa đổi hàm (người dùng định nghĩa)
16 DROP FUNCTION Xóa hàm (người dùng định nghĩa)
17 CREATE TRIGGER Tạo trigger



18 ALTER TRIGGER Sửa đổi trigger
19 DROP TRIGGER Xóa trigger


<b>III </b> <b>Điều khiển truy cập </b>


1 GRANT Cấp phát quyền cho người sử dụng


</div>
<span class='text_page_counter'>(33)</span><div class='page_container' data-page=33>

Các câu lệnh của SQL đều được bắt đầu bởi các từ lệnh. Từ lệnh là một từ
khóa cho biết chức năng của câu lệnh, chẳng hạn: SELECT, INSERT,
COMMIT… sau từ lệnh là các mệnh đề của câu lệnh. Mỗi một mệnh đề trong
câu lệnh cũng được bắt đầu bằng từ khóa.


<i>2.2.2.1. Truy xuất dữ liệu với câu lệnh SELECT </i>


Câu lệnh SELECT được sử dụng để truy xuất dữ liệu từ các dòng và các
cột của một hay nhiều bảng, khung nhìn. Câu lệnh này có thể dùng để thực hiện
phép chọn, phép chiếu và phép kết nối. Ngoài ra, câu lệnh còn cung cấp khả
năng thực hiện các thao tác truy vấn và thống kê dữ liệu phức tạp khác.


Cú pháp chung của câu lệnh SELECT có dạng:


SELECT [ALL | DISTINCT][TOP n] danh_sách_chọn
[INTO Tên_bảng_mới]


FROM Danh_sách_bảng/khung_nhìn
[WHERE Điều_kiện]


[GROUP BY danh_sách_cột]
[HAVING Điều_kiện]



[ORDER BY cột_sắp_xếp]


[COMPUTE danh_sách_hàm_gộp [BY danh_sách_cột]]


<i>Lưu ý: </i>


Câu lệnh SELECT khi được dùng cần tuân thủ đúng trình tự cú pháp trên.
Nếu không, câu lệnh bị xem là không hợp lệ.


Câu lệnh SELECT sử dụng để tác động đến một hoặc một tập hợp các
bảng dữ liệu và kết quả của câu lệnh trả về dưới dạng bảng. Tức là bao gồm một
tập các hàng và các cột.


Các câu lệnh SELECT có thể sử dụng lồng nhau.
<i>2.2.2.2. Bổ sung, cập nhật và xóa dữ liệu </i>


Các câu lệnh thao tác dữ liệu trong SQL không những chỉ sử dụng để truy
vấn dữ liệu mà còn để thay đổi và cập nhật dữ liệu trong cơ sở dữ liệu. So với câu
lệnh SELECT, việc sử dụng các câu lệnh để bổ sung, cập nhật hay xoá dữ liệu
đơn giản hơn nhiều. Trong phần còn lại của chương này sẽ đề cập đến 3 câu lệnh:


 Lệnh INSERT


 Lệnh UPDATE


</div>
<span class='text_page_counter'>(34)</span><div class='page_container' data-page=34>

<b>2.3. Thủ tục (Stored procedure) </b>


<i><b>2.3.1. Các khái niệm </b></i>



SQL được thiết kế và cài đặt như là một ngôn ngữ để thực hiện các thao
tác trên cơ sở dữ liệu như tạo lập các cấu trúc trong cơ sở dữ liệu, bổ sung, cập
nhật, xóa và truy vấn dữ liệu trong cơ sở dữ liệu.


Các câu lệnh SQL được người dùng viết và yêu cầu hệ quản trị cơ sở dữ
liệu thực hiện theo chế độ tương tác.


Các câu lệnh SQL có thể được nhúng vào trong các ngơn ngữ lập trình,
thơng qua đó chuỗi các thao tác trên cơ sở dữ liệu được xác định và thực thi nhờ
vào các câu lệnh, các cấu trúc điều khiển của bản thân ngơn ngữ lập trình được
sử dụng.


Với thủ tục lưu trữ, một phần nào đó khả năng của ngôn ngữ lập trình
được đưa vào trong ngơn ngữ SQL. Một thủ tục là một đối tượng trong cơ sở dữ
liệu bao gồm một tập nhiều câu lệnh SQL được nhóm lại với nhau thành một
nhóm với những khả năng sau:


- Các cấu trúc điều khiển (IF, WHILE, FOR) có thể được sử dụng trong
thủ tục.


- Bên trong thủ tục lưu trữ có thể sử dụng các biến như trong ngơn ngữ
lập trình nhằm lưu giữ lại các giá trị tính tốn được, các giá trị được truy xuất từ
cơ sở dữ liệu.


- Một tập hợp các câu lệnh SQL được kết hợp lại với nhau thành một
khối lệnh bên trong một thủ tục. Một thủ tục có thể nhận các giá trị truyền vào
cũng như có thể trả về các giá trị thông qua các tham số (như trong các ngơn ngữ
lập trình).


- Khi một thủ tục lưu trữ đã được định nghĩa, nó có thể được gọi thơng


qua tên thủ tục, nhận các tham số truyền vào, thực thi các câu lệnh SQL bên
trong thủ tục và có thể trả về các giá trị sau khi thực hiện xong.


Sử dụng các thủ tục lưu trữ trong cơ sở dữ liệu sẽ giúp tăng hiệu năng của
cơ sở dữ liệu, mang lại các lợi ích sau:


<i>Đơn giản hóa các thao tác trên cơ sở dữ liệu nhờ vào khả năng module </i>
hóa các thao tác này: Thủ tục được thiết lập trong từng CSDL một lần nhưng có
thể gọi thực thi nhiều lần trong một hoặc nhiều ứng dụng.


</div>
<span class='text_page_counter'>(35)</span><div class='page_container' data-page=35>

theo cách thông thường. Hơn nữa, khi cần thực hiện một lượng lớn các câu lệnh
T-SQL, thủ tục lưu trữ thực hiện nhanh hơn vì khi máy chủ nhận được nhiều câu
lệnh cùng một lúc đều phải kiểm tra tính hợp lệ về quyền truy xuất của tài khoản
từ máy khách và các tham số khác. Khi thủ tục cần gọi nhiều lần trên các máy
khách thì thủ tục thực hiện một lần đầu tiên, những lần sau máy khách sẽ chạy
thủ tục đã được biên dịch.


<i>Giảm lưu lượng truyền tải trên mạng: Thủ tục lưu trữ cho phép ta thực </i>
hiện cùng một yêu cầu bằng một câu lệnh đơn giản thay vì phải sử dụng nhiều
dịng lệnh SQL. Do đó, khi sử dụng thủ tục lưu trữ thì lưu lượng thơng tin của
lệnh truyền qua mạng sẽ giảm đáng kể.


<i>An ninh, bảo mật hơn: Thay vì cấp phát quyền trực tiếp cho người sử </i>
dụng trên các câu lệnh SQL và trên các đối tượng cơ sở dữ liệu, ta có thể cấp
phát quyền cho người sử dụng thông qua các thủ tục lưu trữ, nhờ đó tăng khả
năng bảo mật đối với hệ thống.


Tuy có những lợi thế nhất định nêu trên nhưng khi sử dụng Stored
Procedure còn tồn tại một số nhược điểm sau:



<i>Stored Procedure làm cho database servertốn nhiều tài nguyên cả về bộ </i>
<i>nhớ lẫn xử lý. Thay vì tập trung vào tính năng lưu trữ và nhận dữ liệu, database </i>
server còn phải thực hiện một loạt các tính tốn hoặc thao tác xử lý phức tạp vốn
khơng phải chức năng chính của database server.


<i>Stored Procedure chỉ chứa đứng các khai báo SQL, vì vậy khó có thể viết </i>
<i>một thủ tục nhằm thực hiện các thao tác xử lý phức tạp như các ngôn ngữ khác </i>
làm được ở tầng ứng dụng như C#, VB, Java, …


Việc tạo lập và bảo trì thủ tục thường yêu cầu một loạt các kỹ năng
chuyên biệt nhiều khi không phải là kỹ năng lập trình của một lập trình viên.
Điều này dẫn đến các vấn đề trong khía cạnh phát triển ứng dụng và bảo trì sản
phẩm.


<i><b>2.3.2. Các loại thủ tục </b></i>


<b>System Stored Procedure: Là thủ tục được lưu trữ trong CSDL Master, </b>
thủ tục loại này được bắt đầu bằng chữ sp_; thường được sử dụng trong quản trị
CSDL và an ninh bảo mật.


</div>
<span class='text_page_counter'>(36)</span><div class='page_container' data-page=36>

trong CSDL do người dùng tạo ra, thực hiện một cơng việc nào đó. Thủ tục loại
này thường được tạo bởi DBA (Database Administrator) hoặc người lập trình.


<b>Temporary Stored Procedure: Có chức năng tương tự như Local Stored </b>
Procedure nhưng thủ tục loại này tự hủy kết nối tạo ra nó ngắt hoặc SQL
SERVER ngưng hoạt động và nó được tạo ra trên CSDL TempDB.


<b>Extended Stored Procedure: Đây là thủ tục sử dụng chương trình ngoại </b>
vi đã được biên dịch thành DLL. Tên thủ tục được bắt đầu bằng xp_. Ví dụ: Thủ
tục xp_sendmail dùng để gửi mail.



<b>Remote Stored Procedure: Là loại thủ tục sử dụng để gọi thủ tục của </b>
một server khác


<i><b>2.3.3. Tạo thủ tục lưu trữ </b></i>


Thủ trục lưu trữ được tạo bởi câu lệnh CREATE PROCEDURE với cú
pháp sau:


CREATE {proc|PROCEDURE}[Ten_thu_tuc][<danh sach tham
so>]


[WITH RECOMPILE | ENCRYPTION | RECOMPILE, ENCRYPTION]
AS


<Cac_cau_lenh_cua_thu_tuc>
<i>Trong đó: </i>


[<Ten_thu_tuc>] Là tên của thủ tục cần tạo. Tên này phải tuân
theo quy tắc định danh và không được vượt quá
128 ký tự.


[<danh_sach_tham_so>] Các tham số của thủ tục được khai báo ngay sau
tên thủ tục và nếu thủ tục có nhiều tham số thì
các tham số phân cách nhau bởi dấu phẩy. Khai
báo của mỗi một tham số tối thiểu phải bao gồm
hai phần:


 Tên tham số được bắt đầu bởi ký tự @



</div>
<span class='text_page_counter'>(37)</span><div class='page_container' data-page=37>

RECOMPILE Thông thường, thủ tục sẽ được phân tích, tối ưu
và dịch sẵn ở lần gọi đầu tiên. Nếu tùy chọn
WITH RECOMPILE được chỉ định, thủ tục sẽ
được dịch lại mỗi khi được triệu gọi.


ENCRYPTION Thủ tục sẽ được mã hóa nếu tùy chọn WITH
ENCRYOTION được chí định. Nếu thủ tục đã
được mã hóa, ta khơng thể xem nội dung của thủ
tục được.


<Cac cau lenh cua thu tuc> Tập hợp các câu lệnh sử dụng trong nội dung
thủ tục. các lệnh này có thể đặt trong cặp từ
khịa BEGIN…END hoặc có thể khơng.


<i><b>Ví dụ: Giả sử cần thực hiện một chuỗi các thao tác như sau trên cơ sở dữ liệu: </b></i>


 Bổ sung thêm mơn học lập trình với cơ sở dữ liệu có mã BK01 và số tín
chỉ là 3 vào bảng MonHoc.


 Lên danh sách nhập điểm thi mơn CSDL cho các sinh viên học lớp có
mã HT0812 (Bổ sung thêm vào bảng DiemThi các bản ghi với cột MaMonHoc
nhận giá trị BK01, cột MaSV nhận giá trị lần lượt là các sinh viên học lớp có mã
HT0812 và các cột điểm nhập là NULL).


Thực hiện yêu cầu trên thông qua các câu lệnh SQL thông thường, ta phải
thực hiện hai câu lệnh như sau:


INSERT INTO MonHoc


VALUES ('BK01', 'Lap Trinh voi CSDL', 3)


INSERT INTO DiemThi (MaMonHoc, MaSV)


SELECT 'BK01', MaSVFROM SinhVienWHERE MaLop = 'HT0812'


Thay vì phải sử dụng hai câu lệnh như trên, ta có thể định nghĩa một thủ
tục lưu trữ với các tham số truyền vào là @MaMonHoc, @TenMonHoc,
@SoTC, @MaLop như sau:


CREATE PROCEDURE sp_LenDanhSachDiem(
@MaMonHoc NVARCHAR(10),


</div>
<span class='text_page_counter'>(38)</span><div class='page_container' data-page=38>

BEGIN


INSERT INTO MonHoc


VALUES(@MaMonHoc,@TenMonHoc, @SoTC)
INSERT INTO DiemThi(MaMonHoc, MaSV)
SELECT @MaMonHoc, MaSV


FROM SinhVien


WHERE MaLop=@MaLop
END


Khi thủ tục được tạo ra, ta có thể thực hiện được hai yêu cầu trên bằng
một cách đơn giản thông qua lời gọi thủ tục:


Sp_LenDanhSachDiem 'BK01', 'Lap Trinh voi CSDL', 3,
'HT0812'



<i><b>2.3.4. Sử dụng biến trong thủ tục </b></i>


Ngoài những tham số được truyền cho thủ tục, bên trong thủ tục cịn có
thể sử dụng các biến nhằm lưu giữ các giá trị tính toán được hoặc truy xuất được
từ cơ sở dữ liệu. các biến trong thủ tục được khai báo bằng từ khóa DECLARE
theo cú pháp như sau:


DECLARE @<Ten_bien><Kieu_du_lieu>


Tên biến phải bắt đầu bởi ký tự @ và tuân theo quy tắc định danh.


<i><b>Ví dụ: Trong định nghĩa thủ tục dưới đây sử dụng các biến chứa các giá trị </b></i>
truy xuất được từ cơ sở dữ liệu cho biết hai lớp nhập học cùng năm hay khác năm:


CREATE PROCEDURE sp_Example(@malop1 CHAR(10), @malop2
CHAR(10))


AS


DECLARE @TenLop1 nvarchar(30)
DECLARE @NamNhapHoc1 INT


DECLARE @TenLop2 nvarchar(30)
DECLARE @NamNhapHoc2 INT


SELECT @TenLop1=TenLop, @NamNhapHoc1=NamNhapHoc
FROM LOP WHERE MaLop=@MaLop1


SELECT @TenLop2=TenLop, @NamNhapHoc2=NamNhapHoc
FROM LOP where MaLop=@MaLop2



IF @NamNhapHoc1 = @NamNhapHoc2
PRINT 'Hai lop nhap hoc cung nam'
ELSE


</div>
<span class='text_page_counter'>(39)</span><div class='page_container' data-page=39>

<i><b>2.3.5. Giá trị trả về của tham số trong thủ tục lưu trữ </b></i>


Trong các ví dụ trước, nếu đối số truyền cho thủ tục khi có lời gọi đến thủ
tục là biến, những thay đổi giá trị của biến trong thủ tục sẽ không được giữ lại
khi kết thúc quá trình thực hiện thủ tục.


<i><b>Ví dụ: Xét câu lệnh sau: </b></i>


CREATE PROCEDURE sp_Conghaiso(@a INT,@b INT, @c INT
OUTPUT)


AS


SELECT @c=@a+@b


Nếu sau khi đã tạo thủ tục với câu lệnh trên, ta thực thi một tập các câu
lệnh như sau:


Thực hiện phép cộng giữa các biến a và b;


Gán kết quả phép cộng vừa tính được cho biến c.


Trong trường hợp cần phải giữ lại giá trị của đối số sau khi kết thúc thủ
tục, ta phải khai báo tham số của thủ tục theo cú pháp như sau:



@<Ten_tham_so><Kieu_du_lieu> OUTPUT
hoặc:


@<Ten_tham_so><Kieu_du_lieu> OUT


và trong lời gọi thủ tục, sau đối số được truyền cho thủ tục, ta cũng phải
chỉ định thêm từ khố OUTPUT (hoặc OUT)


<i><b>Ví dụ: Ta định nghĩa lại thủ tục ở ví dụ trên như sau: </b></i>


CREATE PROCEDURE sp_Conghaiso(
@a INT,


@b INT,


@c INT OUTPUT)
AS


SELECT @c=@a+@b


và thực hiện lời gọi thủ tục trong một tập các câu lệnh như sau:
DECLARE @tong INT


SELECT @tong=0


EXECUTE sp_Conghaiso 150,200,@tong OUTPUT
SELECT @tong


</div>
<span class='text_page_counter'>(40)</span><div class='page_container' data-page=40>

<i><b>2.3.6. Tham số với giá trị mặc định </b></i>



Các tham số được khai báo trong thủ tục có thể nhận các giá trị mặc định.
Giá trị mặc định sẽ được gán cho tham số trong tường hợp không truyền đối số
cho tham số khi có lời gọi đến thủ tục.


Tham số với giá trị mặc định được khai báo theo cú pháp sau:
@<Ten_tham_so><Kieu_du_lieu> = Gia_tri_mac_dinh


<i><b>Ví dụ: </b></i>


CREATE PROC sp_TestDefault(
@tenlop NVARCHAR(50)=NULL,


@noisinh NVARCHAR(200)='HÀ NỘI')
AS


BEGIN


IF @tenlop IS NULL
SELECT hodem,ten


FROM sinhvien INNER JOIN lop
ON sinhvien.malop=lop.malop
WHERE noisinh=@noisinh


ELSE


SELECT hodem,ten


FROM sinhvien INNER JOIN lop
ON sinhvien.malop=lop.malop


WHERE noisinh=@noisinh AND
tenlop=@tenlop


END


Thủ tục sp_TestDefault được định nghĩa với tham số @tenlop có giá trị
mặc định là NULL và tham số @noisinh có giá trị mặc định là HÀ NỘI. Với
thủ tục được định nghĩa như trên, ta có thể thực hiện các lời gọi với các mục
đích khác nhau như sau:


- Cho biết họ tên của các sinh viên sinh tại HÀ NỘI:


sp_testdefault


- Cho biết họ tên của các sinh viên lớp Tin K24 sinh tại Huế:


sp_testdefault @tenlop='HTTT K58'


- Cho biết họ tên của các sinh viên sinh tại Nghệ An:


sp_testDefault @noisinh=N'Hà Nội'


- Cho biết họ tên của các sinh viên lớp Tin K26 sinh tại Đà Nẵng:


</div>
<span class='text_page_counter'>(41)</span><div class='page_container' data-page=41>

<i><b>2.3.7. Sửa đổi thủ tục </b></i>


Khi một thủ tục đã được tạo ra, ta có thể tiến hành định nghĩa lại thủ tục
đó bằng câu lệnh ALTER PROCDURE với cú pháp như sau:


ALTER PROCEDURE ten_thu_tuc [<danh_sach_tham_so>]


[WITH RECOMPILE|ENCRYPTION|RECOMPILE,ENCRYPTION]
AS


Cac_cau_lenh_cua_thu_tuc


Câu lệnh này sử dụng tương tự như câu lệnh CREATE PROCEDURE.
Việc sửa đổi lại một thủ tục đã có khơng làm thay đổi đến các quyền đã cấp phát
trên thủ tục cũng như không tác động đến các thủ tục khác hay trigger phụ thuộc
vào thủ tục này.


<i><b>2.3.8. Xoá thủ tục </b></i>


Để xố một thủ tục đã có, ta sử dụng câu lệnh DROP PROCEDURE với
cú pháp như sau:


DROP PROCEDURE ten_thu_tuc


Khi xoá một thủ tục, tất cả các quyền đã cấp cho người sử dụng trên thủ
tục đó cũng đồng thời bị xố bỏ. Do đó, nếu tạo lại thủ tục, ta phải tiến hành cấp
phát lại các quyền trên thủ tục đó.


<i><b>2.3.9. Thực thi một thủ tục lưu trữ </b></i>


Khi một thủ tục lưu trữ được tạo ra, ta có thể yêu cầu hệ quản trị cơ sở dữ
liệu thực thi thủ tục thơng qua lời gọi thủ tục có dạng:


<Ten_thu_tuc><danh_sach_cac_doi_so>


Số lượng các đối số cũng như thứ tự sắp xếp chúng phải phù hợp với số
lượng và thứ tự của các tham số khi định nghĩa thủ tục.



Trong trường hợp lời gọi thủ tục được thực hiện bên trong một thủ tục
khác, bên trong một trigger hay kết hợp với các câu lệnh SQL khác, ta sử dụng
cú pháp như sau:


EXCUTE <Ten_thu_tuc><Danh sach cac doi so>


Thứ tự của các đối số được truyền cho thủ tục có thể không cần phải tuân
theo thứ tự các tham số như khi định nghĩa thủ tục nếu tất cả các đối số được
viết dưới dạng:


@<Ten_Tham_So> = <gia_trị>


<i><b>Ví dụ: Lời gọi thủ tục ở ví dụ trên có thể được viết như sau: </b></i>


</div>
<span class='text_page_counter'>(42)</span><div class='page_container' data-page=42>

@TenMonHoc = 'Lap Trinh voi CSDL'
@SoTC = 3


<b>Lưu ý: </b>


Thủ tục khi được tạo ra có thể được triệu gọi trong các ứng dụng .NET.
Ví dụ, đối với windows form sau đây:


Trong thủ tục nội tại của SQL SERVER, ta sẽ viết 1 Store Procedure đơn
giản có tên GetSV nhằm lấy về danh sách các sinh viên trong bảng SINHVIEN
từ cơ sở dữ liệu như sau:


CREATE PROC [dbo].[GetSV]
AS



SELECT * FROM SinhVien


Để đưa dữ liệu trả về từ thủ tục nội tại GetSV lên đối tượng dataGridview
khi giao diện “Quản lý thông tin sinh viên”, ta khai báo 1 hàm như sau:


private void GetListSV()
{


//Khai báo chuỗi kết nối đến SQL SERVER:


string conn = "Data Source=.\\SQLEXPRESS;Initial
Catalog=QuanLyThucTap;Integrated Security=True";
//Khai báo đối tượng kết nối đến SQL SERVER:
SQLConnection SQLCon = new SQLConnection(conn);


//Gọi kết quả thủ tục lưu trữ được đưa vào đối tượng
DataAdapter:


SQLDataAdapter daSV = new SQLDataAdapter("GetSV",
SQLCon);


//Khai báo sử dụng 1 đối tượng DataTable:
DataTable dtSV = new DataTable();


//Lấy dữ liệu từ DataAdapter vào bảng:
daSV.Fill(dtSV);


</div>
<span class='text_page_counter'>(43)</span><div class='page_container' data-page=43>

dataGridView:


dataGridView1.DataSource = dtSV;


}


Như vậy, để cài đặt hiển thị dữ liệu khi giao diện này được triệu gọi thì
trong sự kiện Load form, ta chỉ cần gọi hàm GetListSV() vừa khai báo ở trên.


private void Form1_Load(object sender, EventArgs e)
{


GetListSV();
}


Kết quả trả về sau khi thực hiện như sau:


Sử việc gọi 1 store procedure trong C# cũng tương tự như việc gọi 1 câu
lệnh SQL vào bài tốn. Đối với các Store Procedure có chứa các biến thì ta cần
sử dụng đối tượng Parameter để tạo ra các tham số và truyền vào giá trị cho các
tham số trong thủ tục Store procedure thường dùng khi làm việc với đối tượng
Command với CommandType là StoreProcedure! Lúc này, các Parameter sẽ
được tạo ra với Name, DataType, Size hay loại tham số là Input hay Output,...
tương ứng với các tham số trong Store procedure của HQT Database!


<b>2.4. Hàm người dùng định nghĩa (Functions) </b>


Hàm là đối tượng cơ sở dữ liệu tương tự như thủ tục. Điểm khác biệt giữa
hàm và thủ tục là hàm trả về một giá trị thơng qua tên hàm cịn thủ tục thì
khơng. Điều này cho phép ta sử dụng hàm như là một thành phần của một biêu
thức (chẳng hạn trong danh sách chọn của câu lệnh SELECT).


</div>
<span class='text_page_counter'>(44)</span><div class='page_container' data-page=44>

<i><b>2.4.1. Định nghĩa và sử dụng hàm </b></i>



Hàm được định nghĩa thông qua câu lệnh CREATE FUNCTION với cú
pháp như sau:


CREATE FUNCTION ten_ham [<Danh_sach_tham_so>]
RETURNS <Kieu_tra_ve_cua_ham>


AS
BEGIN


<cac_cau_lenh_cua_ham>
END


<i><b>Ví dụ: Câu lệnh dưới đây định nghĩa hàm tính ngày trong tuần (thứ trong </b></i>
tuần) của một giá trị kiểu ngày.


CREATE FUNCTION thu(@ngay DATETIME)
RETURNS NVARCHAR(10)


AS
BEGIN


DECLARE @st NVARCHAR(10)


SELECT @st=CASE DATEPART(DW,@ngay)
WHEN 1 THEN 'Chu nhat'


WHEN 2 THEN 'Thu hai'
WHEN 3 THEN 'Thu ba'
WHEN 4 THEN 'Thu tu'
WHEN 5 THEN 'Thu nam'


WHEN 6 THEN 'Thứ sáu'
ELSE 'Thứ bảy'


END


RETURN (@st) /* Trị trả về của hàm */
END


Một hàm khi đã được định nghĩa có thể được sử dụng như các hàm do hệ
quản trị cơ sở dữ liệu cung cấp (thông thường trước tên hàm ta phải chỉ định
thêm tên của người sở hữu hàm)


<i><b>Ví dụ: Câu lệnh SELECT dưới đây sử dụng hàm đã được định nghĩa ở ví </b></i>
dụ trước:


SELECT masv,hodem,ten,dbo.thu(ngaysinh),ngaysinh
FROM sinhvien


WHERE malop= 'C24102'


<i><b>2.4.2. Hàm với giá trị trả về là “dữ liệu kiểu bảng” </b></i>


</div>
<span class='text_page_counter'>(45)</span><div class='page_container' data-page=45>

khung nhìn trong cơ sở dữ liệu. Tuy nhiên, nếu cần phải sử dụng các tham số
trong khung nhìn (chẳng hạn các tham số trong mệnh đề WHERE của câu lệnh
SELECT) thì ta lại không thể thực hiện được. Điều này phần nào đó làm giảm
tính linh hoạt trong việc sử dụng khung nhìn.


<i><b>Ví dụ: Xét khung nhìn được định nghĩa như sau: </b></i>


CREATE VIEW sinhvien_k58


AS


SELECT masv,hodem,ten,ngaysinh
FROM sinhvien INNER JOIN lop
ON sinhvien.malop=lop.malop
WHERE khoa=58


Với khung nhìn trên, thơng qua câu lệnh:


SELECT * FROM sinhvien_K58


Ta có thể biết được danh sách các sinh viên khoá 58 một cách dễ dàng
nhưng rõ ràng không thể thơng qua khung nhìn này để biết được danh sách sinh
viên các khố khác do khơng thể sử dụng điều kiện có dạng KHOA = @thaMSo
trong mệnh đề WHERE của câu lệnh SELECT được.


Nhược điểm trên của khung nhìn có thể khắc phục bằng cách sử dụng
hàm với giá trị trả về dưới dạng bảng và được gọi là hàm nội tuyến (inline
function). Việc sử dụng hàm loại này cung cấp khả năng như khung nhìn nhưng
cho phép chúng ta sử dụng được các tham số và nhờ đó tính linh hoạt sẽ cao
hơn. Một hàm nội tuyến được định nghĩa bởi câu lệnh CREATE TABLE với cú
pháp như sau:


CREATE FUNCTION Ten_ham [<Danh_sach_tham_so>]
RETURNS TABLE


AS


RETURN (cau_lenh_SELECT)



Cú pháp của hàm nội tuyến phải tuân theo các qui tắc sau:


- Kiểu trả về của hàm phải được chỉ định bởi mệnh đề RETURNS
TABLE.


- Trong phần thân của hàm chỉ có duy nhất một câu lệnh RETURN xác
định giá trị trả về của hàm thông qua duy nhất một câu lệnh SELECT. Ngồi ra,
khơng sử dụng bất kỳ câu lệnh nào khác trong phần thân của hàm.


<i><b>Ví dụ: Ta định nghĩa hàm func_XeMSV như sau: </b></i>


</div>
<span class='text_page_counter'>(46)</span><div class='page_container' data-page=46>

RETURNS TABLE
AS


RETURN(SELECT masv,hodem,ten,ngaysinh
FROM sinhvien INNER JOIN lop


ON sinhvien.malop=lop.malop
WHERE khoa=@khoa)


Hàm trên nhận tham số đầu vào là khóa của sinh viên cần xem và giá trị
trả về của hàm là tập các dòng dữ liệu cho biết thông tin về các sinh viên của
khố đó. Các hàm trả về giá trị dưới dạng bảng được sử dụng như là các bảng
hay khung nhìn trong các câu lệnh SQL.


Với hàm được định nghĩa như trên, để biết danh sách các sinh viên khoá
53, ta sử dụng câu lệnh như sau:


SELECT * FROM dbo.func_XeMSV(53)



còn câu lệnh dưới đây cho ta biết được danh sách sinh viên khoá 36:
SELECT * FROM dbo.func_XeMSV(36)


Đối với hàm nội tuyến, phần thân của hàm chỉ cho phép sự xuất hiện duy
nhất của câu lệnh RETURN. Trong trường hợp cần phải sử dụng đến nhiều câu
lệnh trong phần thân của hàm, ta sử dụng cú pháp như sau để định nghĩa hàm:


CREATE FUNCTION ten_ham [<danh_sach_tham_so>]
RETURNS @bien_bang TABLE dinh_nghia_bang


AS
BEGIN


Cac_cau_lenh_trong_than_ham
RETURN


END


<b>Khi định nghĩa hàm dạng này cần lưu ý một số điểm sau: </b>


- Cấu trúc của bảng trả về bởi hàm được xác định dựa vào định nghĩa
của bảng trong mệnh đề RETURNS. Biến <i>@bien_bang</i> trong mệnh đề
RETURNS có phạm vi sử dụng trong hàm và được sử dụng như là một tên bảng.


- Câu lệnh RETURN trong thân hàm không chỉ định giá trị trả về. Giá trị
trả về của hàm chính là các dịng dữ liệu trong bảng có tên là @biếnbảng được
định nghĩa trong mệnh đề RETURNS.


</div>
<span class='text_page_counter'>(47)</span><div class='page_container' data-page=47>

<i><b>Ví dụ: Ta định nghĩa hàm func_TongSV như sau: </b></i>



CREATE FUNCTION Func_Tongsv(@khoa SMALLINT)
RETURNS @bangthongke TABLE


(


MaKhoa NVARCHAR(5),
TenKhoa NVARCHAR(50),
TongSoSV INT


)
AS
BEGIN


IF @khoa=0


INSERT INTO @bangthongke


SELECT khoa.makhoa,tenkhoa,COUNT(masv)
FROM KHOA INNER JOIN LOP ON


KHOA.Makhoa=LOP.MaKhoa


INNER JOIN SINHVIEN ON LOP.MaLop=SINHVIEN.MaLop
GROUP BY KHOA.MaKhoa, TenKhoa


ELSE


INSERT INTO @bangthongke


SELECT khoa.makhoa,tenkhoa,COUNT(masv)


FROM khoa INNER JOIN lop ON


khoa.makhoa=lop.makhoa


INNER JOIN sinhvien ON lop.malop=sinhvien.malop
WHERE khoa=@khoa


GROUP BY khoa.makhoa,tenkhoa
RETURN /*Trả kết quả về cho hàm*/
END


Với hàm được định nghĩa như trên, câu lệnh sau:
SELECT * FROM dbo.func_TongSV(25)


Sẽ cho kết quả thống kê tổng số sinh viên khoá 25 của mỗi khoa:
Còn câu lệnh:


SELECT * FROM dbo.func_TongSV(0)


Cho ta biết tổng số sinh viên hiện có (tất cả các khố) của mỗi khoa
<b>2.5. Trigger </b>


</div>
<span class='text_page_counter'>(48)</span><div class='page_container' data-page=48>

sở dữ liệu cũng với mục đích này là các trigger. Cũng tương tự như thủ tục lưu
trữ, một trigger là một đối tượng chứa một tập các câu lệnh SQL và tập các câu
lệnh này sẽ được thực thi khi trigger được gọi. Điểm khác biệt giữa thủ tục lưu
trữ và trigger là: Các thủ tục lưu trữ được thực thi khi người sử dụng có lời gọi
đến chúng cịn các trigger lại được “gọi” tự động khi xảy ra những giao tác làm
thay đổi dữ liệu trong các bảng.


Mỗi một trigger được tạo ra và gắn liền với một bảng nào đó trong cơ sở dữ


liệu. Khi dữ liệu trong bảng bị thay đổi (tức là khi bảng chịu tác động của các câu
lệnh INSERT, UPDATE hay DELETE) thì trigger sẽ được tự động kích hoạt.


Sử dụng trigger một cách hợp lý trong cơ sở dữ liệu sẽ có tác động rất lớn
trong việc tăng hiệu năng của cơ sở dữ liệu. Các trigger thực sự hữu dụng với
những khả năng sau:


- Một trigger có thể nhận biết, ngăn chặn và huỷ bỏ được những thao tác
làm thay đổi trái phép dữ liệu trong cơ sở dữ liệu.


- Các thao tác trên dữ liệu (xoá, cập nhật và bổ sung) có thể được trigger
phát hiện ra và tự động thực hiện một loạt các thao tác khác trên cơ sở dữ liệu
nhằm đảm bảo tính hợp lệ của dữ liệu.


- Thơng qua trigger, ta có thể tạo và kiểm tra được những mối quan hệ
phức tạp hơn giữa các bảng trong cơ sở dữ liệu mà bản thân các ràng buộc
không thể thực hiện được.


<i><b>2.5.1. Định nghĩa trigger </b></i>


Ta đã biết các ràng buộc được sử dụng để đảm bảo tính toàn vẹn dữ liệu
trong cơ sở dữ liệu. Một đối tượng khác cũng thường được sử dụng trong các cơ
sở dữ liệu cũng với mục đích này là các trigger. Cũng tương tự như thủ tục lưu
trữ, một trigger là một đối tượng chứa một tập các câu lệnh SQL và tập các câu
lệnh này sẽ được thực thi khi trigger được gọi. Điểm khác biệt giữa thủ tục lưu
trữ và trigger là: các thủ tục lưu trữ được thực thi khi người sử dụng có lời gọi
đến chúng cịn các trigger lại được “gọi” tự động khi xảy ra những giao tác làm
thay đổi dữ liệu trong các bảng.


Mỗi một trigger được tạo ra và gắn liền với một bảng nào đó trong cơ sở dữ


liệu. Khi dữ liệu trong bảng bị thay đổi (tức là khi bảng chịu tác động của các câu
lệnh INSERT, UPDATE hay DELETE) thì trigger sẽ được tự động kích hoạt.


</div>
<span class='text_page_counter'>(49)</span><div class='page_container' data-page=49>

những khả năng sau:


- Một trigger có thể nhận biết, ngăn chặn và huỷ bỏ được những thao tác
làm thay đổi trái phép dữ liệu trong cơ sở dữ liệu.


- Các thao tác trên dữ liệu (xố, cập nhật và bổ sung) có thể được trigger
phát hiện ra và tự động thực hiện một loạt các thao tác khác trên cơ sở dữ liệu
nhằm đảm bảo tính hợp lệ của dữ liệu.


- Thơng qua trigger, ta có thể tạo và kiểm tra được những mối quan hệ
phức tạp hơn giữa các bảng trong cơ sở dữ liệu mà bản thân các ràng buộc
không thể thực hiện được.


<i>2.5.1.1. Định nghĩa Trigger </i>


Một trigger là một đối tượng gắn liền với một bảng và được tự động kích
hoạt khi xảy ra những giao tác làm thay đổi dữ liệu trong bảng. Định nghĩa một
trigger bao gồm các yếu tố sau:


- Trigger sẽ được áp dụng đối với bảng nào?


- Trigger được kích hoạt khi câu lệnh nào được thực thi trên bảng:
INSERT, UPDATE, DELETE?


- Trigger sẽ làm gì khi được kích hoạt?


Câu lệnh CREATE TRIGGER được sử dụng để đinh nghĩa trigger và có


cú pháp như sau:


CREATE TRIGGER tên_trigger
ON tên_bảng


FOR {[INSERT][,][UPDATE][,][DELETE]}
AS


[IF UPDATE(tên_cột)


[AND UPDATE(tên_cột)|OR UPDATE(tên_cột)]
...]


các_câu_lệnh_của_trigger
<b>Ví dụ: Ta định nghĩa các bảng như sau: </b>


Bảng MATHANG lưu trữ dữ liệu về các mặt hàng:
CREATE TABLE mathang


(


mahang NVARCHAR(5) PRIMARY KEY, /*mã hàng*/
tenhang NVARCHAR(50) NOT NULL, /*tên hàng*/
soluong INT, /*số lýợng hàng hiện có*/


)


</div>
<span class='text_page_counter'>(50)</span><div class='page_container' data-page=50>

CREATE TABLE nhatkybanhang
(



stt INT IDENTITY PRIMARY KEY,
ngay DATETIME, /*ngày bán hàng*/


nguoimua NVARCHAR(30), /*tên ngýời mua hàng*/
mahang NVARCHAR(5) /*mã mặt hàng ðýợc bán*/
FOREIGN KEY REFERENCES mathang(mahang),
soluong INT, /*giá bán hàng*/


giaban MONEY /*số lýợng hàng ðýợc bán*/
)


<i>Câu lệnh dưới đây định nghĩa trigger trg_nhatkybanhang_insert. Trigger </i>
này có chức năng tự động giảm số lượng hàng hiện có khi một mặt hàng nào đó
được bán (tức là khi câu lệnh INSERT được thực thi trên bảng
NHATKYBANHANG).


CREATE TRIGGER trg_nhatkybanhang_insert
ON nhatkybanhang


FOR INSERT
AS


UPDATE mathang


SET mathang.soluong=mathang.soluong-inserted.soluong
FROM mathang INNER JOIN inserted


ON mathang.mahang=inserted.mahang


Với trigger vừa tạo ở trên, nếu dữ liệu trong bảng MATHANG là:



thì sau khi ta thực hiện câu lệnh:
INSERT INTO


nhatkybanhang(ngay,nguoimua,mahang,soluong,giaban)
VALUES('5/5/2004','Tran Ngoc Thanh','H1',10,5200)
dữ liệu trong bảng MATHANG sẽ như sau:


</div>
<span class='text_page_counter'>(51)</span><div class='page_container' data-page=51>

sẽ kích hoạt trigger (FOR INSERT). Ngồi INSERT, ta cịn có thể chỉ định
UPDATE hoặc DELETE cho mệnh đề này, hoặc có thể kết hợp chúng lại với
nhau. Phần thân của trigger nằm sau từ khoá AS bao gồm các câu lệnh mà
trigger sẽ thực thi khi được kích hoạt.


Chuẩn SQL định nghĩa hai bảng logic INSERTED và DELETED để sử
dụng trong các trigger. Cấu trúc của hai bảng này tương tự như cấu trúc của
bảng mà trigger tác động. Dữ liệu trong hai bảng này tuỳ thuộc vào câu lệnh tác
động lên bảng làm kích hoạt trigger; cụ thể trong các trường hợp sau:


- Khi câu lệnh DELETE được thực thi trên bảng, các dịng dữ liệu bị xố
sẽ được sao chép vào trong bảng DELETED. Bảng INSERTED trong trường
hợp này khơng có dữ liệu.


- Dữ liệu trong bảng INSERTED sẽ là dòng dữ liệu được bổ sung vào
bảng gây nên sự kích hoạt đối với trigger bằng câu lệnh INSERT. Bảng
DELETED trong trường hợp này khơng có dữ liệu.


- Khi câu lệnh UPDATE được thực thi trên bảng, các dòng dữ liệu cũ
chịu sự tác động của câu lệnh sẽ được sao chép vào bảng DELETED, còn trong
bảng INSERTED sẽ là các dòng sau khi đã được cập nhật.



<i><b>2.5.2. Sử dụng mênh đề if update trong trigger </b></i>


Thay vì chỉ định một trigger được kích hoạt trên một bảng, ta có thể chỉ
định trigger được kích hoạt và thực hiện những thao tác cụ thể khi việc thay đổi
dữ liệu chỉ liên quan đến một số cột nhất định nào đó của cột. Trong trường hợp
này, ta sử dụng mệnh đề IF UPDATE trong trigger. IF UPDATE không sử dụng
được đối với câu lệnh DELETE.


<b>Ví dụ: Xét lại ví dụ với hai bảng MATHANG và NHATKYBANHANG, </b>
trigger dưới đây được kích hoạt khi ta tiến hành cập nhật cột SOLUONG cho
một bản ghi của bảng NHATKYBANHANG (lưu ý là chỉ cập nhật đúng một
bản ghi).


CREATE TRIGGER trg_nhatkybanhang_update_soluong
ON nhatkybanhang


FOR UPDATE
AS


IF UPDATE(soluong)
UPDATE mathang


</div>
<span class='text_page_counter'>(52)</span><div class='page_container' data-page=52>

(inserted.soluong-deleted.soluong)
FROM (deleted INNER JOIN inserted ON


deleted.stt = inserted.stt) INNER JOIN mathang
ON mathang.mahang = deleted.mahang


Với trigger ở ví dụ trên, câu lệnh:
UPDATE nhatkybanhang


SET soluong=soluong+20
WHERE stt=1


sẽ kích hoạt trigger ứng với mệnh đề IF UPDATE (soluong) và câu lệnh
UPDATE trong trigger sẽ được thực thi. Tuy nhiên câu lệnh:


UPDATE nhatkybanhang


SET nguoimua='Mai Hữu Tồn'
WHERE stt=3


lại khơng kích hoạt trigger này.


Mệnh đề IF UPDATE có thể xuất hiện nhiều lần trong phần thân của
trigger. Khi đó, mệnh đề IF UPDATE nào đúng thì phần câu lệnh của mệnh đề
đó sẽ được thực thi khi trigger được kích hoạt.


<b>Ví dụ: Giả sử ta định nghĩa bảng R như sau: </b>
CREATE TABLE R


(


A INT,
B INT,
C INT
)


<i>và trigger trg_R_update cho bảng R: </i>


CREATE TRIGGER trg_R_test


ON R


FOR UPDATE
AS


IF UPDATE(A)


Print 'A updated'
IF UPDATE(C)


Print 'C updated'


</div>
<span class='text_page_counter'>(53)</span><div class='page_container' data-page=53>

C=100 WHERE C=2cũng kích hoạt trigger và cho kết quả là: C updated;
còn câu lệnh: UPDATE R SET B=100 WHERE B=3 hiển nhiên sẽ khơng
kích hoạt trigger.


<i><b>2.5.3. Rollback transaction và trigger </b></i>


Một trigger có khả năng nhận biết được sự thay đổi về mặt dữ liệu trên
bảng dữ liệu, từ đó có thể phát hiện và huỷ bỏ những thao tác không đảm bảo
tính tồn vẹn dữ liệu. Trong một trigger, để huỷ bỏ tác dụng của câu lệnh làm
kích hoạt trigger, ta sử dụng câu lệnh:


ROLLBACK TRANSACTION


<b>Ví dụ: Nếu trên bảng MATHANG, ta tạo một trigger như sau: </b>
CREATE TRIGGER trg_mathang_delete


ON mathang
FOR DELETE


AS


ROLLBACK TRANSACTION


Thì câu lệnh DELETE sẽ khơng thể có tác dụng đối với bảng
MATHANG. Hay nói cách khác, ta khơng thể xố được dữ liệu trong bảng.


<b>Ví dụ: Trigger dưới đây được kích hoạt khi câu lệnh INSERT được sử </b>
dụng để bổ sung một bản ghi mới cho bảng NHATKYBANHANG. Trong
trigger này kiểm tra điều kiện hợp lệ của dữ liệu là số lượng hàng bán ra phải
nhỏ hơn hoặc bằng số lượng hàng hiện có. Nếu điều kiện này khơng thoả mãn
thì huỷ bỏ thao tác bổ sung dữ liệu.


CREATE TRIGGER trg_nhatkybanhang_insert
ON NHATKYBANHANG


FOR INSERT
AS


DECLARE @sl_co int /* Số lượng hàng hiện có */
DECLARE @sl_ban int /* Số lượng hàng được bán */
DECLARE @mahang nvarchar(5) /* Mã hàng được bán */


SELECT @mahang=mahang,@sl_ban=soluong
FROM inserted


SELECT @sl_co = soluong


</div>
<span class='text_page_counter'>(54)</span><div class='page_container' data-page=54>

/*Nếu số lượng hàng hiện có nhỏ hơn số lượng bán
thì huỷ bỏ thao tác bổ sung dữ liệu */



IF @sl_co<@sl_ban
ROLLBACK TRANSACTION
/* Nếu dữ liệu hợp lệ


thì giảm số lượng hàng hiện có */
ELSE


UPDATE mathang


SET soluong=soluong-@sl_ban
WHERE mahang=@mahang


<i><b>2.5.4. Sử dụng trigger trong trường hợp insert, update và delete có tác động </b></i>
<i><b>đến nhiều dòng dữ liệu </b></i>


Trong các ví dụ trước, các trigger chỉ thực sự hoạt động đúng mục đích
khi các câu lệnh kích hoạt trigger chỉ có tác dụng đối với đúng một dịng dữ liêu.
Ta có thể nhận thấy là câu lệnh UPDATE và DELETE thường có tác dụng trên
nhiều dịng, câu lệnh INSERT mặc dù ít rơi vào trường hợp này nhưng khơng
phải là khơng gặp; đó là khi ta sử dụng câu lệnh có dạng INSERT INTO...
SELECT ... Vậy làm thế nào để trigger hoạt động đúng trong trường hợp những
câu lệnh có tác động lên nhiều dịng dữ liệu?


Có hai giải pháp có thể sử dụng đối với vấn đề này:
- Sử dụng truy vấn con.


- Sử dụng biến con trỏ.
<i>2.5.4.1. Sử dụng truy vấn con </i>



</div>
<span class='text_page_counter'>(55)</span><div class='page_container' data-page=55>

Trigger dưới đây cập nhật lại số lượng hàng của bảng MATHANG khi
câu lệnh UPDATE được sử dụng để cập nhật cột SOLUONG của bảng
NHATKYBANHANG.


CREATE TRIGGER trg_nhatkybanhang_update_soluong
ON nhatkybanhang


FOR UPDATE
AS


IF UPDATE(soluong)
UPDATE mathang


SET mathang.soluong = mathang.soluong –
(inserted.soluong-deleted.soluong)


FROM (deleted INNER JOIN inserted ON


deleted.stt = inserted.stt) INNER JOIN mathang
ON mathang.mahang = deleted.mahang


Với trigger được định nghĩa như trên, nếu thực hiện câu lệnh:
UPDATE nhatkybanhang


SET soluong = soluong + 10
WHERE stt = 1


thì dữ liệu trong hai bảng MATHANG và NHATKYBANHANG sẽ là:


Bảng MATHANG Bảng NHATKYBANHANG



<i>Tức là số lượng của mặt hàng có mã H1 đã được giảm đi 10. Nhưng nếu </i>
thực hiện tiếp câu lệnh:


UPDATE nhatkybanhang
SET soluong=soluong + 5
WHERE mahang='H2'


dữ liệu trong hai bảng sau khi câu lệnh thực hiện xong sẽ như sau:


</div>
<span class='text_page_counter'>(56)</span><div class='page_container' data-page=56>

<i>Ta có thể nhận thấy số lượng của mặt hàng có mã H2 cịn lại 40 (giảm đi </i>
<i>5) trong khi đúng ra phải là 35 (tức là phải giảm 10). Như vậy, trigger ở trên </i>
không hoạt động đúng trong trường hợp này.


Để khắc phục lỗi gặp phải như trên, ta định nghĩa lại trigger như sau:
CREATE TRIGGER trg_nhatkybanhang_update_soluong
ON nhatkybanhang


FOR UPDATE
AS


IF UPDATE(soluong)
UPDATE mathang


SET mathang.soluong = mathang.soluong -


(SELECT SUM(inserted.soluong-deleted.soluong)
FROM inserted INNER JOIN deleted


ON inserted.stt=deleted.stt



WHERE inserted.mahang = mathang.mahang)
WHERE mathang.mahang IN (SELECT mahang
FROM inserted)


hoặc:


CREATE TRIGGER trg_nhatkybanhang_update_soluong
ON nhatkybanhang


FOR UPDATE
AS


IF UPDATE(soluong)


/* Nếu số lượng dòng được cập nhật bằng 1 */
IF @@ROWCOUNT = 1


BEGIN


UPDATE mathang


SET mathang.soluong = mathang.soluong –
(inserted.soluong-deleted.soluong)


FROM (deleted INNER JOIN inserted ON


deleted.stt = inserted.stt) INNER JOIN mathang
ON mathang.mahang = deleted.mahang



END
ELSE
BEGIN


UPDATE mathang


SET mathang.soluong = mathang.soluong -


</div>
<span class='text_page_counter'>(57)</span><div class='page_container' data-page=57>

FROM inserted INNER JOIN deleted
ON inserted.stt=deleted.stt


WHERE inserted.mahang = mathang.mahang)
WHERE mathang.mahang IN (SELECT mahang
FROM inserted)


END


<i>2.5.4.2. Sử dụng biến con trỏ </i>


Một cách khác để khắc phục lỗi xảy ra như trong ví dụ ở trên là sử dụng
con trỏ để duyệt qua các dòng dữ liệu và kiểm tra trên từng dòng. Tuy nhiên, sử
dụng biến con trỏ trong trigger là giải pháp nên chọn trong trường hợp thực sự
cần thiết.


Một biến con trỏ được sử dụng để duyệt qua các dòng dữ liệu trong kết
quả của một truy vấn và được khai báo theo cú pháp như sau:


DECLARE tên_con_trỏ CURSOR
FOR câu_lệnh_SELECT



Trong đó câu lệnh SELECT phải có kết quả dưới dạng bảng. Tức là trong
câu lệnh không sử dụng mệnh đề COMPUTE và INTO.


Để mở một biến con trỏ ta sử dụng câu lệnh:
OPEN tên_con_trỏ


Để sử dụng biến con trỏ duyệt qua các dòng dữ liệu của truy vấn, ta sử
dụng câu lệnh FETCH. Giá trị của biến trạng thái @@FETCH_STATUS bằng
khơng nếu chưa duyệt hết các dịng trong kết quả truy vấn.


Câu lệnh FETCH có cú pháp như sau:


FETCH [[NEXT|PRIOR|FIST|LAST] FROM] tên_con_trỏ
[INTO danh_sách_biến ]


Trong đó các biến trong danh sách biến được sử dụng để chứa các giá trị
của các trường ứng với dòng dữ liệu mà con trỏ trỏ đến. Số lượng các biến phải
bằng với số lượng các cột của kết quả truy vấn trong câu lệnh DECLARE
CURSOR.


<b>Ví dụ: Tập các câu lệnh trong ví dụ dưới đây minh hoạ cách sử dụng biến </b>
con trỏ để duyệt qua các dòng trong kết quả của câu lệnh SELECT


DECLARE contro CURSOR


FOR SELECT mahang,tenhang,soluong FROM mathang
OPEN contro


DECLARE @mahang NVARCHAR(10)
DECLARE @tenhang NVARCHAR(10)


DECLARE @soluong INT


</div>
<span class='text_page_counter'>(58)</span><div class='page_container' data-page=58>

FETCH NEXT FROM contro


INTO @mahang,@tenhang,@soluong
WHILE @@FETCH_STATUS=0


BEGIN


PRINT 'Ma hang:'+@mahang
PRINT 'Ten hang:'+@tenhang


PRINT 'So luong:'+STR(@soluong)
FETCH NEXT FROM contro


INTO @mahang,@tenhang,@soluong
END


/*Ðóng con trỏ và giải phóng vùng nhớ*/
CLOSE contro


DEALLOCATE contro


<b>Ví dụ: Trigger đây là một cách giải quyết khác của trường hợp được đề cập </b>
ở trên.


CREATE TRIGGER trg_nhatkybanhang_update_soluong
ON nhatkybanhang


FOR UPDATE


AS


IF UPDATE(soluong)
BEGIN


DECLARE @mahang NVARCHAR(10)
DECLARE @soluong INT


DECLARE contro CURSOR FOR
SELECT inserted.mahang,


inserted.soluong-deleted.soluong AS soluong
FROM inserted INNER JOIN deleted


ON inserted.stt=deleted.stt
OPEN contro


FETCH NEXT FROM contro INTO @mahang,@soluong
WHILE @@FETCH_STATUS=0


BEGIN


UPDATE mathang SET soluong=soluong-@soluong
WHERE mahang=@mahang


FETCH NEXT FROM contro INTO @mahang,@soluong
END


CLOSE contro



DEALLOCATE contro
END


</div>
<span class='text_page_counter'>(59)</span><div class='page_container' data-page=59>

<b>TÀI LIỆU THAM KHẢO </b>


<i>1. Mike Chapple (2009). Microsoft SQL SERVER 2008 for Dummies. </i>
Wiley Publishing, Inc.


<i>2. Ramez Elmasri, Shamkant B. Navathe (2010). Fundamentals of </i>
<i>Database systeMS. 6</i>th edition, Addison-Wesley.


<i>3. Phạm Hữu Khang, Đoàn Thiện Ngân (2007). SQL SERVER 2005 - Lập </i>
<i>trình T-SQL. NXB Lao động - Xã hội. </i>


<i>4. Phạm Hữu Khang, Đoàn Thiện Ngân (2008). SQL SERVER 2005 - Lập </i>
<i>trình Thủ tục và hàm. NXB Lao động - Xã hội. </i>


<i>5. Phạm Hữu Khang, Phương Lan (2009). Microsoft SQL SERVER 2008 – </i>
<i>Quản trị cơ sở dữ liệu, tập 1. NXB Lao động – Xã hội. </i>


<i>6. Phạm Hữu Khang, Phương Lan (2010). Microsoft SQL SERVER 2008 – </i>
<i>Quản trị cơ sở dữ liệu, tập 2. NXB Lao động – Xã hội. </i>


</div>
<span class='text_page_counter'>(60)</span><div class='page_container' data-page=60>

<b>Câu hỏi và bài tập: </b>
Cho sơ đồ cơ sở dữ liệu Quản lý bán hàng như dưới đây:


1. Dùng câu lệnh định nghĩa dữ liệu để thực hiện tạo cơ sở dữ liệu và các
bảng với những ràng buộc trên?


2. Tạo thủ tục lưu trữ để thông qua thủ tục này có thể bổ sung thêm


một bản ghi mới cho bảng MATHANG (thủ tục phải thực hiện kiểm tra tính
hợp lệ của dữ liệu cần bổ sung: khơng trùng khố chính và đảm bảo tồn vẹn
tham chiếu).


3. Tạo thủ tục lưu trữ có chức năng thống kê tổng số lượng hàng bán được
của một mặt hàng có mã bất kỳ (mã mặt hàng cần thống kê là tham số của thủ tục).
4. Viết hàm trả về một bảng trong đó cho biết tổng số lượng hàng bán
được của mỗi mặt hàng. Sử dụng hàm này để thống kê xem tổng số lượng hàng
(hiện có và đã bán) của mỗi mặt hàng là bao nhiêu.


5. Viết trigger cho bảng CHITIETDATHANG theo yêu cầu sau:


• Khi một bản ghi mới được bổ sung vào bảng này thì giảm số lượng
hàng hiện có nếu số lượng hàng hiện có lớn hơn hoặc bằng số lượng hàng được
bán ra. Ngược lại thì huỷ bỏ thao tác bổ sung.


</div>
<span class='text_page_counter'>(61)</span><div class='page_container' data-page=61>

<b>Chương 3 </b>


<b>THIẾT KẾ ỨNG DỤNG THEO MƠ HÌNH NHIỀU LỚP </b>
<i>Mục tiêu: </i>


<i>- Giới thiệu mơ hình thiết kế ứng dụng theo mơ hình nhiều lớp; </i>
<i>- Giới thiệu mơ hình lập trình 3 lớp; </i>


<i>- Thiết kế ứng dụng theo mơ hình 3 lớp qua ví dụ cụ thể. </i>
<b>3.1. Giới thiệu mơ hình nhiều lớp </b>


Trước đây, đối với những phần mềm có sử dụng liên quan đến dữ liệu,
thường khi viết chương trình, Lập trình viên sẽ tích hợp việc giao tiếp với người
sử dụng, xử lý rồi ghi xuống dữ liệu trên cùng một đối tượng, có thể là FORM,


CLASS… Tuy nhiên, việc lập trình bắt đầu trở lên phức tạp khi dự án lớn dần
nếu vẫn sử dụng phương pháp đó. Bởi vậy để dễ quản lý các thành phần của hệ
thống, cũng như không bị ảnh hưởng bởi các thay đổi, người ta hay nhóm các
thành phần có cùng chức năng lại với nhau và phân chia trách nhiệm cho từng
nhóm để cơng việc khơng bị chồng chéo và ảnh hưởng lẫn nhau. Một trong
những mơ hình lập trình như vậy chính là Mơ hình 3 lớp (Three Layers).


Ví dụ 1: Trong một Trường Đại học có từng Khoa chun mơn, mỗi Khoa
chuyên môn sẽ chịu trách nhiệm giảng dạy, chủ nhiệm một ngành/nhóm ngành
nào đó, Khoa này khơng được can thiệp vào công việc chuyên môn của Khoa
khác, chẳng hạn như Khoa Kinh tế thì giảng dạy các mơn học của khối ngành
Kinh tế, còn chuyện dạy kiến thức gì cho các sinh viên thì các Giảng viên của
Khoa Công nghệ thông tin không cần biết, và cũng không quan tâm.


Trong phát triển phần mềm, người ta cũng áp dụng cách phân chia chức
năng này để chia nhỏ bài toán thành những thành phần nhỏ hơn, mỗi thành phần
thực hiện một công việc riêng rẽ, tách rời… Vậy, cách phân chia đó có những
lợi điểm và hạn chế nào? Để làm rõ hơn về điều này, chúng ta cùng đi xem xét
kiến trúc mơ hình.


<b>3.2. Kiến trúc mơ hình </b>


</div>
<span class='text_page_counter'>(62)</span><div class='page_container' data-page=62>

mình và sẽ sử dụng nó như thế nào mà thơi. Có thể biểu diễn các thành phần này
trong sơ đồ sau:


<b>Hình 3.1. Kiến trúc mơ hình 3 lớp </b>
<b>3.3. Lớp trình diễn dữ liệu (Presentation layers – PL) </b>


Đây là phần tương tác với người dùng hoặc các hệ thống bên ngoài nhằm
thu thập dữ liệu và hiển thị kết quả/dữ liệu thông qua các thành phần trong giao


diện người sử dụng. Lớp trình diễn dữ liệu sẽ sử dụng các dịch vụ do lớp
Business Logic cung cấp. Trong môi trường .NET có thể dung Windows
ForMS; ASP.NET hay Mobile ForMS để thực hiện.


<i>Presentation Layers gồm 2 thành phần chính là User Interface </i>
Components và User Interface Process Components.


Thành phần User Interface Components chính là các phần tử chịu trách
nhiệm thu thập và hiển thị thông tin cho người dùng cuối. Các thành phần này
có thể là TextBox; Button; DataGrid…


</div>
<span class='text_page_counter'>(63)</span><div class='page_container' data-page=63>

<i>Lưu ý: Không nên sử dụng các kết nối dữ liệu trực tiếp từ lớp này vì nếu </i>
sử dụng tực tiếp có thể người lập trình sẽ bỏ qua các ràng buộc, các logic nghiệp
vụ mà ứng dụng cần phải có. Hơn nữa, nếu sử dụng trực tiếp thì sẽ khơng cịn
tính chất của mơ hình 3 lớp.


<b>3.4. Lớp xử lý logic (Business Logic Layer – BLL) </b>


Lớp xử lý logic thực hiện nghiệp vụ chính của hệ thống, sử dụng các dịch
vụ do lớp Data Access cung cấp và cung cấp các dịch vụ cho lớp Presentation.
Lớp này cũng có thể sử dụng các dịch vụ của các nhà cung cấp thứ 3 để thực
hiện công việc của mình.


Thành phần chính: Services Interface; Business Components và Business
Entities.


<i>Service Interface: Là giao diện lập trình mà lớp này cung cấp cho lớp </i>
Presentation sử dụng. Lớp Presentation chỉ cần biết các dịch vụ thông qua giao diện
này mà không cần quan tâm đến bên trong lớp này được thực hiện như thế nào.



<i>Business Components: Là các thành phần chính thực hiện các dịch vụ mà </i>
Service Interface cung cấp. Chịu trách nhiệm kiểm tra các ràng buộc logic
(constraints), các quy tắc nghiệp vụ (Business Rules), sử dụng các dịch vụ bên
ngoài khác để thực hiện các yêu cầu của ứng dụng.


<i>Business Entities: Là những thực thể mô tả những đối tượng thông tin mà </i>
hệ thống xử lý. Các Business Entities này được dùng để trao đổi thông tin giữa
lớp Presentation và lớp Data Access Layer.


<b>3.5. Lớp truy cập dữ liệu (Data Access Layer – DAL) </b>


Lớp truy cập dữ liệu thực hiện các nghiệp vụ liên quan đến lưu trữ và truy
xuất dữ liệu của ứng dụng. Thông thường, lớp này sẽ sử dụng các dịch vụ của
các hệ quản trị cơ sở dữ liệu như SQL SERVER, Oracle,… hoặc dữ liệu tác
nghiệp có thể truy xuất từ một tệp tin (text, binary, XML…) để thực hiện nghiệp
vụ của mình. Đối với cơ sở dữ liệu, lớp này thực hiện kết nối trực tiếp với cơ sở
dữ liệu và thực hiện tất cả các thao tác liên quan đến cơ sở dữ liệu mà phần mềm
cần thiết. Đối với tệp tin, lớp này thực hiện việc đọc, ghi tệp theo yêu cầu của
phần mềm. Việc thực hiện này sẽ do lớp xử lý logic triệu gọi.


Các thành phần chính của lớp này bao gồm: Data Access Logic
Components, Data Sources, Service Agents.


</div>
<span class='text_page_counter'>(64)</span><div class='page_container' data-page=64>

systeMS… Trong .NET các DAL này thường được hiện thực bằng cách sử dụng
thư viện ADO.NET để giao tiếp với các hệ cơ sở dữ liệu lưu trữ trong CSDL.


Service Agents là các thành phần trợ giúp việc truy xuất dữ dịch vụ bên
ngoài một cách dễ dàng và đơn giản như truy cập các dịch vụ nội tại.


<i><b>Ví dụ: Trong giao diện winform login và cơ sở dữ liệu như sau sau: </b></i>



Form Đăng nhập đóng vai trị là lớp trình diễn dữ liệu, chỉ thực hiện cơng
việc nhận thông số từ người dùng và kiểm tra sơ bộ thông tin được nhập từ
người dùng xem thơng tin đó có được nhập đúng quy tắc hay không và hiển thị
các thơng báo.


• Khi thiết kế theo mơ hình 3 lớp, thành phần Thu nhận, hiển thị thông tin
(UI Components) chính là các Lable, TextBox, Button trên form.


• Trong C#.NET cho phép thiết kế trực quan bằng phương pháp “kéo thả”
Thành phần hiển thị và thu nhận dữ liệu gồm các textbox, lable, button.
Được khai báo như sau trong C#:


namespace Demo
{


partial class Form1
{


/// <summary>


/// Required designer variable.
/// </summary>


</div>
<span class='text_page_counter'>(65)</span><div class='page_container' data-page=65>

/// <summary>


/// Clean up any resources being used.
/// </summary>


/// <param name="disposing">true if managed


resources should be disposed; otherwise,


false.</param>


protected override void Dispose(bool
disposing)


{


if (disposing && (components != null))
{


components.Dispose();
}


base.Dispose(disposing);
}


#region Windows Form Designer generated code
/// <summary>


/// Required method for Designer support - do
not modify


/// the contents of this method with the code
editor.


/// </summary>


private void InitializeComponent()


{


this.lbTrangThaiDangNhap = new
System.Windows.ForMS.Label();


this.btn_Huy = new
System.Windows.ForMS.Button();


this.btn_DangNhap = new
System.Windows.ForMS.Button();


</div>
<span class='text_page_counter'>(66)</span><div class='page_container' data-page=66>

this.txt_User = new
System.Windows.ForMS.TextBox();
this.SuspendLayout();
//


// lbTrangThaiDangNhap
//


this.lbTrangThaiDangNhap.AutoSize = true;
this.lbTrangThaiDangNhap.Location = new
System.Drawing.Point(179, 165);


this.lbTrangThaiDangNhap.Margin = new
System.Windows.ForMS.Padding(4, 0, 4, 0);


this.lbTrangThaiDangNhap.Name =
"lbTrangThaiDangNhap";


this.lbTrangThaiDangNhap.Size = new


System.Drawing.Size(180, 17);


this.lbTrangThaiDangNhap.TabIndex = 13;
this.lbTrangThaiDangNhap.Text = "Trạng
thái chưa đăng nhập";


//


// btn_Huy
//


this.btn_Huy.DialogResult =
System.Windows.ForMS.DialogResult.Cancel;
this.btn_Huy.Location = new
System.Drawing.Point(301, 201);


this.btn_Huy.Margin = new
System.Windows.ForMS.Padding(4);


this.btn_Huy.Name = "btn_Huy";
this.btn_Huy.Size = new


System.Drawing.Size(143, 42);


this.btn_Huy.TabIndex = 11;
this.btn_Huy.Text = "Hủy";


this.btn_Huy.UseVisualStyleBackColor =
true;



</div>
<span class='text_page_counter'>(67)</span><div class='page_container' data-page=67>

// btn_DangNhap
//


this.btn_DangNhap.DialogResult =
System.Windows.ForMS.DialogResult.OK;


this.btn_DangNhap.Location = new
System.Drawing.Point(88, 201);


this.btn_DangNhap.Margin = new
System.Windows.ForMS.Padding(4);


this.btn_DangNhap.Name = "btn_DangNhap";
this.btn_DangNhap.Size = new


System.Drawing.Size(143, 42);


this.btn_DangNhap.TabIndex = 12;


this.btn_DangNhap.Text = "Đăng nhập";
this.btn_DangNhap.UseVisualStyleBackColor
= true;


this.btn_DangNhap.Click += new
System.EventHandler(this.btn_DangNhap_Click);
//


// label2
//



this.label2.AutoSize = true;
this.label2.Location = new
System.Drawing.Point(85, 121);


this.label2.Margin = new


System.Windows.ForMS.Padding(5, 0, 5, 0);
this.label2.Name = "label2";
this.label2.Size = new


System.Drawing.Size(70, 17);


this.label2.TabIndex = 10;


this.label2.Text = "Mật khẩu:";
//


// label3
//


this.label3.AutoSize = true;
this.label3.Font = new


</div>
<span class='text_page_counter'>(68)</span><div class='page_container' data-page=68>

System.Drawing.GraphicsUnit.World, ((byte)(0)));
this.label3.Location = new


System.Drawing.Point(168, 9);


this.label3.Margin = new



System.Windows.ForMS.Padding(5, 0, 5, 0);
this.label3.Name = "label3";
this.label3.Size = new


System.Drawing.Size(203, 36);


this.label3.TabIndex = 8;


this.label3.Text = "ĐĂNG NHẬP";
//


// label1
//


this.label1.AutoSize = true;
this.label1.Location = new
System.Drawing.Point(85, 83);


this.label1.Margin = new


System.Windows.ForMS.Padding(5, 0, 5, 0);
this.label1.Name = "label1";
this.label1.Size = new


System.Drawing.Size(75, 17);


this.label1.TabIndex = 9;


this.label1.Text = "Tài khoản:";
//



// txt_Pas
//


this.txt_Pas.Location = new
System.Drawing.Point(170, 118);


this.txt_Pas.Margin = new
System.Windows.ForMS.Padding(5);


this.txt_Pas.Name = "txt_Pas";
this.txt_Pas.PasswordChar = '*';
this.txt_Pas.Size = new


System.Drawing.Size(271, 23);


this.txt_Pas.TabIndex = 7;
//


</div>
<span class='text_page_counter'>(69)</span><div class='page_container' data-page=69>

//


this.txt_User.Location = new
System.Drawing.Point(170, 80);


this.txt_User.Margin = new
System.Windows.ForMS.Padding(5);


this.txt_User.Name = "txt_User";
this.txt_User.Size = new



System.Drawing.Size(271, 23);


this.txt_User.TabIndex = 6;
//


// Form1
//


this.AutoScaleDimensions = new
System.Drawing.SizeF(8F, 16F);


this.AutoScaleMode =


System.Windows.ForMS.AutoScaleMode.Font;
this.ClientSize = new


System.Drawing.Size(534, 283);


this.Controls.Add(this.lbTrangThaiDangNhap);
this.Controls.Add(this.btn_Huy);


this.Controls.Add(this.btn_DangNhap);
this.Controls.Add(this.label2);


this.Controls.Add(this.label3);
this.Controls.Add(this.label1);
this.Controls.Add(this.txt_Pas);
this.Controls.Add(this.txt_User);
this.Font = new



System.Drawing.Font("Microsoft Sans Serif", 10F,
System.Drawing.FontStyle.Regular,


System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.FormBorderStyle =


System.Windows.ForMS.FormBorderStyle.FixedSingle;
this.Margin = new


</div>
<span class='text_page_counter'>(70)</span><div class='page_container' data-page=70>

System.Windows.ForMS.ForMStartPosition.CenterScreen;
this.Text = "Form1";


this.ResumeLayout(false);
this.PerformLayout();
}


#endregion


private System.Windows.ForMS.Label
lbTrangThaiDangNhap;


private System.Windows.ForMS.Button btn_Huy;
private System.Windows.ForMS.Button


btn_DangNhap;


private System.Windows.ForMS.Label label2;
private System.Windows.ForMS.Label label3;
private System.Windows.ForMS.Label label1;


private System.Windows.ForMS.TextBox txt_Pas;
private System.Windows.ForMS.TextBox


txt_User;
}
}


Giao diện sau khi thiết kế như hình dưới đây:


Khi người dùng nhập dữ liệu vào form đăng nhập và nhấn chọn “Đăng
nhập”, thành phần xử lý tín hiệu đầu vào của lớp trình diễn dữ liệu sẽ thực hiện
công việc kiểm tra sơ bộ dữ liệu đầu vào được nhập từ người dùng. Q trình xử
lý tín hiệu đầu vào này sẽ được thực hiện khi nguời dùng nhấn vào nút “Đăng
nhập” trên giao diện trên.


namespace Demo
{


</div>
<span class='text_page_counter'>(71)</span><div class='page_container' data-page=71>

{


public Form1()
{


InitializeComponent();
}


UserBUS ubus = new UserBUS();


private void btn_DangNhap_Click(object
sender, EventArgs e)



{


if (txt_User.Text=="")
{


lbTrangThaiDangNhap.Text = "Không
được để trống Tên đăng nhập";


}


else if (txt_Pas.Text=="")
{


lbTrangThaiDangNhap.Text = "Không
được để trống Mật khẩu";


}
else
{


if(ubus.Check(txt_User.Text,txt_Pas.Text)==true)
{


lbTrangThaiDangNhap.Text="Đăng
nhập thành công";


}
}


}


private void btn_Huy_Click(object sender,
EventArgs e)


{


this.Close();
}


}
}


Tại lớp xử lý nghiệp vụ sẽ thực hiện cơng việc chính của đăng nhập, đó là
kiểm tra xem dữ liệu truyền vào từ lớp presentation có trùng khớp với dữ liệu
đang có trong cơ sở dữ liệu hay không bằng cách gọi dịch vụ của lớp
DataAccessLayers:


using Demo.DataAccess;


</div>
<span class='text_page_counter'>(72)</span><div class='page_container' data-page=72>

namespace Demo.BusinessLogic
{


class UserBUS
{


ConnectData conn = new ConnectData();
DAL_User dalUser = new DAL_User();


public bool Check(string username, string


password)


{


User user = new User();


user = dalUser.LayThongTinUser(username);
if (user == null)


{


MessageBox.Show("Tên đăng nhập không
tồn tại");


return false;
}


else if


(string.Compare(password,user.PassWord)==0)
{


MessageBox.Show("Mật khẩu không
đúng");


return false;
}


else
{



MessageBox.Show("Đăng nhập thành
công!");


return true;
}


}
}
}


Tại lớp truy cập dữ liệu sẽ truy cập dữ liệu nằm trong cơ sở dữ liệu và
dùng để cung cấp cho lớp xử lý dữ liệu kiểm tra:


using Demo.DataAccess;


using Demo.Business_Entities;
namespace Demo.DataAccess
{


class DAL_User
{


</div>
<span class='text_page_counter'>(73)</span><div class='page_container' data-page=73>

public User LayThongTinUser(string username)
{


User user = new User();


string SQL = "SELECT UserName, PassWord,
HoTen, Nhom "



+ "FROM Users WHERE Users.UserName
='" + username + "' ";


DataTable tbuser = conn.GetDataTable(SQL);
if (tbuser.Rows.Count > 0)


{


DataRow rowuser = tbuser.Rows[0];
user.UserName =


rowuser["UserName"].ToString();
user.PassWord =
rowuser["PassWord"].ToString();
user.HoTen =
rowuser["HoTen"].ToString();
user.Nhom =
rowuser["Nhom"].ToString();
}


else user = null;
return user;


}
}
}


Hàm này sẽ có nhiệm vụ trả về đối tượng User các thông tin theo tham số
truyền vào (username).



</div>
<span class='text_page_counter'>(74)</span><div class='page_container' data-page=74>

Nếu tên đăng nhập và mật khẩu đã nhập đầy đủ thì thực hiện so sánh các thành
phần này với CSDL đã lưu. Hình dưới đây cho biết tên đăng nhập không tồn tại.


Khi nhập đúng tên đăng nhập và mật khẩu, một thông báo đăng nhập
thành công sẽ mở trong hộp thoai hiện ra, màn hình sẽ hiển thị thơng báo và cho
biết đã đăng nhập với tên người dùng nào


</div>
<span class='text_page_counter'>(75)</span><div class='page_container' data-page=75>

<b>3.6. Ưu việt và hạn chế của mơ hình lập trình nhiều lớp </b>


Qua tìm hiểu về kiến trúc mơ hình lập trình 3 lớp, cùng với việc xem xét
các ví dụ trên ta có thể thấy được những ưu việt khi sử dụng mơ hình này trong
thực tiễn như sau:


 Mã nguồn rõ ràng, rành mạch. Do đó, đọc dễ hiểu, dễ sửa chữa, dễ nhận biết.


 Xử lý, tách biệt, làm tăng hiệu suất ở một số công đoạn, như xử lý
CSDL (truy vấn, tính tốn....); xử lý nghiệp vụ…


 Tạo sự chuyên nghiệp hơn trong công việc: Phù hợp làm việc theo
nhóm, mỗi người được phân cơng một mảng cơng việc riêng rẽ.


 Giúp ích cho việc đơn giản hóa mã nguồn:


 Có tính kế thừa, ví dụ như thay vì viết đi viết lại nhiều câu select,
insert, update… thì giờ chỉ việc truyền tham số table và các value và gọi hàm đó
ra là đủ... Hơn nữa, 1 lớp đối tượng của dự án này có thể được triệu gọi sử dụng
trong các dự án khác.


 Lợi ích trong an tồn và bảo mật hệ thống: Hacker muốn tấn cơng sẽ


khó hơn vì họ chỉ thấy thành phần giao tiếp với người sử dụng mà khơng nhìn
thấy phần khác.


Tuy vậy, mơ hình lập trình nhiều lớp còn tồn tại những hạn chế sau:


 Việc truyền dữ liệu giữa các tầng sẽ chậm hơn vì phải lưu chuyển thơng
qua các tiến trình khác nhau;


 Việc phát triển ứng dụng phức tạp hơn vì phải xác định được các lớp
cơng việc cụ thể rồi mới phân thành các nhóm thực hiện các lớp cơng việc đó.
<b>3.7. Mơ hình MVC (Model – View – Controller) </b>


</div>
<span class='text_page_counter'>(76)</span><div class='page_container' data-page=76>

<b>Hình 3.2. Mơ hình lập trình MVC </b>


<b> Model: Thành phần chứa tất cả các nghiệp vụ logic, phương thức xử lý, </b>
truy xuất database, đối tượng mô tả dữ liệu như các Class, hàm xử lý...


<b> View: Đảm nhận việc hiển thị thông tin, tương tác với người dùng, nơi </b>
chứa tất cả các đối tượng GUI như textbox, images...Hiểu một cách đơn giản, nó
là tập hợp các form hoặc các file HTML.


<b> Controller: Giữ nhiệm vụ nhận điều hướng các yêu cầu từ người dùng </b>
và gọi đúng những phương thức xử lý chúng... Chẳng hạn thành phần này sẽ
nhận request từ url và form để thao tác trực tiếp với Model.


<b>Hoạt động của mơ hình MVC: </b>


<b>Hình 3.3. Hoạt động của MVC </b>


Ở sơ đồ trên, những mũi tên nét đứt được hình thành trên quan điểm của


người dùng mà không phải là của những nhà thiết kế phần mềm thực sự. Do đó,
chúng ta chỉ quan tâm đến những mũi tên còn lại.


Đây là một cách đơn giản để mô tả lại luồng sự kiện được xử lý trong
MVC:


</div>
<span class='text_page_counter'>(77)</span><div class='page_container' data-page=77>

 Controller nhận và điều hướng chúng đến đúng phương thức xử lý ở
Model.


 Model nhận thông tin và thực thi các yêu cầu.


 Khi Model hoàn tất việc xử lý, View sẽ nhận kết quả từ Model và hiển
thị lại cho người dùng.


<b>Hình 3.4. Mơ hình luồng xử lý trong mơ hình MVC </b>
<b>Ưu nhược điểm của mơ hình MVC: </b>


Khi sử dụng mơ hình MVC sẽ thể hiện tính chun nghiệp trong lập trình,
phân tích thiết kế. Do được chia thành các thành phần độc lập nên giúp phát
triển ứng dụng nhanh, đơn giản, dễ nâng cấp, bảo trì…


</div>
<span class='text_page_counter'>(78)</span><div class='page_container' data-page=78>

<b>TÀI LIỆU THAM KHẢO </b>


1. Hans-Petter Halvorsen, Database Communication in Visual Studio/C#
using 3-tier Arcitecture (The examples uses ADO.NET)


2. Website thư viện học tập của Microsoft:


3. Website :
<i><b>Câu hỏi và bài tập: </b></i>



Sử dụng cơ sở dữ liệu cho ở chương 2, thực hiện thiết kế các form có các
chức năng:


</div>
<span class='text_page_counter'>(79)</span><div class='page_container' data-page=79>

<b>Chương 4 </b>


<b>LÀM VIỆC VỚI TẬP TIN XML </b>
<i>Mục tiêu chương này sẽ cung cấp các nội dung: </i>
<i>- Giới thiệu về XML; </i>


<i>- Đọc và Ghi dữ liệu vào tệp tin XML. </i>
<b>4.1. Giới thiệu XML </b>


XML, hoặc eExtensible Markup Language (ngôn ngữ đánh dấu mở rộng),
là một ngơn ngữ đánh dấu có thể sử dụng để tạo ra thẻ riêng của mình. XML
được tạo nên bởi Liên minh mạng toàn cầu nhằm khắc phục những hạn chế của
HTML - ngôn ngữ đánh dấu siêu văn bản, là cơ sở của mọi trang Web. Giống
như HTML, XML cũng được dựa trên SGML – Standard Generalized Markup
Language. Mặc dù SGML được sử dụng trong ngành công nghiệp xuất bản
trong nhiều thập kỷ, nhưng sự phức tạp của nó đều khiến những ai từng sử dụng
nó mà khơng có cách nào khác phải thấy mệt mỏi (một cách nói vui, SGML
cũng là "Sounds great, maybe later").


Ngôn ngữ đánh dấu mở rộng (XML) được mô tả như vừa như là một ngôn
ngữ đánh dấu và vừa như là một định dạng lưu trữ dữ liệu dựa trên văn bản, tùy
thuộc vào đối tượng của cuộc nói chuyện nhắm đến ai. Nó là một tập hợp con
của Ngôn ngữ đánh dấu tổng quát chuẩn (SGML- Standard Generalized Markup
Language); nó cung cấp một phương tiện dựa trên văn bản để áp dụng và mơ tả
một cấu trúc hình cây cho thông tin. XML phục vụ làm cơ sở cho một số ngơn
ngữ/định dạng như Trình tự động cập nhật tệp tin (RSS-Really Simple


Syndication), Ngôn ngữ giao diện người dùng XML (XUL - XML User
Interface Language) của Mozilla, Ngôn ngữ đánh dấu trải nghiệm tối đa
(MXML - Maximum eXperience Markup Language) của Macromedia, Ngôn
ngữ đánh dấu ứng dụng Mở rộng được (XAML - eXtensible Application
Markup Language) của Microsoft và Ngôn ngữ đánh dấu giao diện người dùng
Java XML (XAMJ - Java XML UI Markup Language) mã nguồn mở.


Như vậy chứng tỏ XML có một tầm quan trọng rất lớn. Ta cùng tìm hiểu
về cách làm việc với tập tin XML trong .NET.


<b>4.2. Các không gian tên xử lý XML trong .NET </b>


</div>
<span class='text_page_counter'>(80)</span><div class='page_container' data-page=80>

cũng sử dụng XML cho những file cấu hình và tài liệu mã nguồn, như SOAP,
các dịch vụ Web, và ADO.NET.


Để mở rộng cho việc sử dụng XML, .NET Framework cung cấp không
gian System.XML. Không gian tên này chứa các lớp giúp cho lập trình viên thao
tác trên XML, và trong chương này chúng ta sẽ trình bày các lớp này.


Không gian tên System.XML trong .NET cung cấp một số lớp hỗ trợ cho
việc xử lí XML. Nào hãy xem qua (một cách không thứ tự) một vài lớp quan
trọng trong không gian tên System.XML. Đây là những lớp đọc và viết XML
chính mà chúng tơi sẽ trình bày:


<b>Bảng 4.1. Các khơng gian tên của XML </b>


<b>Tên lớp </b> <b>Giải thích </b>


XMLReader Lớp đọc trừu tượng nhanh và non-cached dữ liệu XML.
XMLReader được thiết kế giống như bộ phân tách SAX.


XMLWriter Lớp viết trừu tượng nhanh và non-cached dữ liệu XML


trong một dòng hoặc định dạng file.


XMLTextReader Mở rộng của XMLReader, hỗ trợ chuỗi truy cập nhanh dữ
liệu XML


XMLTextWriter Mở rộng của XMLWriter, phát nhanh các dòng XML
XMLNote Miêu tả một nút đơn trong 1 tài liệu XML. Lớp này làm


cơ sở cho các lớp khác trong không gian tên XML.


XMLDocument Mở rộng của XMLNote, đây là một thực thi W3C
Document Oject Model (DOM), cung cấp 1 cây miêu tả tài
liệu XML trong bộ nhớ cho phép điều hướng và soạn thảo
XMLDataDocument Mở rộng của XMLDocument. Đây là một tài liệu có thể


được tải từ dữ liệu XML hoặc từ dữ liệu trong một
ADO.NET DataSet. Cho phép hòa trộn XML và dữ liệu
quan hệ trong cùng một view.


XMLResolver Một lớp trừu tượng dùng giải quyết các tài nguyên XML
ngoài như DTD và tham chiếu sơ đồ. Cũng dùng để xử lí
các thành phần <xsl:include> và <xsl:import>.


XMLUrlResolver Mở rộng của XMLResolver. Giải quyết các tài nguyên tên
như một URI (Uniform Resource Identifier).


</div>
<span class='text_page_counter'>(81)</span><div class='page_container' data-page=81>

và dòng XML, trong khi những lớp khác (ví dụ như lớp XMLDataDocument)
cung cấp một cầu nối giữa lưu trữ XML và lưu trữ dữ liệu dữ liệu trong các


DataSet.


<b>4.3. Đọc file XML bằng .NET </b>


Có 3 cách để đọc và duyệt qua nội dung của file XML


 Sử dụng XMLNodeList: Nội dung file XML sẽ được đọc vào memory
bằng cách dùng phương thức Load() của XMLNodeList. Class này cho phép ta
duyệt, tìm kiếm, thay đổi dữ liệu và save ngược lại file


 Sử dụng XPathNavigator: nội dung file XML sẽ được đọc vào
XPathNavigator, đây là class cho phép đọc, duyệt và tìm kiếm dữ liệu nhanh
hơn so với XMLNodeList. Tuy nhiên XPathNavigator khơng có chức năng cập
nhật dữ liệu


 Sử dụng XMLTextReader: là class cho phép duyệt file XML theo
từng node một lần từ đầu cho đến cuối file. Tốc độ duyệt rất nhanh và tốn ít
tài nguyên.


XMLNodeList, XPathNavigator xem nôi dung file XML ở dạng cây phân
cấp, bao gồm các node cha và node con. Trong khi đó, XMLTextReader xem
nôi dung file XML ở dạng văn bản “phẳng” không phân cấp, bao gồm các
element. Vì vậy trong XMLTextReader ta khơng thể có các phương thức di
chuyển như MoveXXX() như XMLNodeList hay XPathNavigator.


Ví dụ:


<?XML version="1.0" encoding="utf-8" ?>
<DVDList>



<DVD ID="1" Category="War" Date="08/07/2008">
<Title id="1">Tear of the Sun</Title>


<Description>The war in Columbia</Description>
<Price>$40,000,000</Price>


<Stars>


<Star>Bruce Willis</Star>
<Star>Monica Bellucci</Star>
</Stars>


</DVD>
</DVDList>


</div>
<span class='text_page_counter'>(82)</span><div class='page_container' data-page=82>

<b>Hình 4.1. Nội dung file được biểu diễn dưới dạng cây </b>


Trong cây XML, tất các các thành phần dữ liệu (trừ Attributes) đều được
coi là node, kể cả các text nằm giữa các thẻ cũng được coi là node. Để phân biệt,
.NET Framework chia làm rất nhiều loại node khác nhau nằm trong enum
XMLNodeType.


Sau đây, ta thiết kế form để load
thông tin bên trong file XML này với
giao diện như sau:


</div>
<span class='text_page_counter'>(83)</span><div class='page_container' data-page=83>

sing System;


using System.Collections.Generic;
using System.ComponentModel;



using System.Data;
using System.Drawing;
using System.LINQ;
using System.Text;


using System.Windows.ForMS;
using System.XML;


namespace Demo
{


public partial class DemoXML : Form
{


public DemoXML()
{


InitializeComponent();
}


private void button1_Click(object sender,
EventArgs e)


{


// Đường dẫn tới file XML.


string fileName = "XMLFile1.XML";
// Tạo một đối tượng TextReader mới


XMLTextReader xtr = new


XMLTextReader(fileName);


while (xtr.Read())
{


if (xtr.NodeType == XMLNodeType.Text)
{


lbXML.IteMS.Add(xtr.Value);
}


}
}
}
}


</div>
<span class='text_page_counter'>(84)</span><div class='page_container' data-page=84>

<i><b>4.3.1. Sử dụng XMLnodelist </b></i>


Nội dung file XML sẽ được đọc vào memory bằng cách dùng phương
thức Load() của XMLNodeList. Class này cho phép ta duyệt, tìm kiếm, thay đổi
dữ liệu và save ngược lại file.


using System;


using System.Collections.Generic;
using System.LINQ;


using System.Text;


using System.XML;


namespace Demo3
{


class Program
{


static void Main(string[] args)
{


string fileName = "XMLFile1.XML";
XMLDocument XMLDocument = new
XMLDocument();


XMLDocument.Load(fileName);
string content =


GetChildNodeContent(XMLDocument.ChildNodes, 0);
}


private static string


GetChildNodeContent(XMLNodeList XMLNodeList,int
level)


{


</div>
<span class='text_page_counter'>(85)</span><div class='page_container' data-page=85>

string indentation = "";



for (int i = 0; i < level; i++)
{


indentation += " ";
}


foreach (XMLNode node in XMLNodeList)
{


sb.Append(indentation);
switch (node.NodeType)
{


case XMLNodeType.XMLDeclaration:
sb.Append("XML Declaration:
");


sb.Append(node.Name);
sb.Append(" ");


sb.AppendLine(node.Value);
break;


case XMLNodeType.Comment:
sb.Append("Comment: ");
sb.AppendLine(node.Value);
break;


case XMLNodeType.Element:
sb.Append("Element: ");


sb.AppendLine(node.Name);
break;


case XMLNodeType.Text:
sb.Append("- Value:");
sb.AppendLine(node.Value);
break;


default:
break;
}


// Read attributes


if (node.Attributes != null)
{


foreach (XMLAttribute attribute
in node.Attributes)


{


</div>
<span class='text_page_counter'>(86)</span><div class='page_container' data-page=86>

sb.Append("'" +
attribute.Name + "'");


sb.Append(" Value:");
sb.AppendLine("'" +
attribute.Value + "'");


}


}


// Read child nodes
if (node.HasChildNodes)
{




sb.Append(GetChildNodeContent(node.ChildNodes, level
+ 1));


}
}


return sb.ToString();
}


}
}


<i><b>4.3.2. Sử dụng xpathnavigator </b></i>


XPathNavigator hoạt động giống như XMLDocument, nó load tồn bộ dữ
liệu XML vào vùng nhớ và có cũng có thể truy cập đến từng node. Tuy nhiên
XPathNavigator cung cấp rất nhiều các phương thức giúp chuyển đến các node
một cách dễ dàng


MoveTo(): Chuyển đến một node được chỉ định
MoveChild(): Chuyển đến node con được chỉ định
MoveFirstChild(): Chuyển đến node con đầu tiên



MoveToFirst(): Chuyển đến node anh em (cùng cấp) đầu tiên
MoveNext(): Chuyển đến node anh em kế tiếp


MovePrevious(): Chuyển đến node anh em ngay trước
MoveToFirstAttribute(): Chuyển đến thuộc tính đầu tiên của node
MoveToNextAttribute(): Chuyển đến thuộc tính kế tiếp của node
MoveToParent(): Chuyển đến node cha


</div>
<span class='text_page_counter'>(87)</span><div class='page_container' data-page=87>

using System.Collections.Generic;
using System.LINQ;


using System.Text;
using System.XML;


using System.XML.XPath;
namespace Demo3


{


class Program
{


static void Main(string[] args)
{


string fileName = " XMLFile1.XML ";
// Load XML file to document


XMLDocument XMLDocument = new XMLDocument();


XMLDocument.Load(fileName);


// Create XPathNavigator


XPathNavigator xPathNav
=XMLDocument.CreateNavigator();
// Get content


string content =
GetXPathNavContent(xPathNav, 0);
}


private static string


GetXPathNavContent(XPathNavigator xNav, int level)
{


string indentation = "";


for (int i = 0; i < level; i++)
{


indentation += " ";
}


StringBuilder sb = new StringBuilder();
sb.Append(indentation);


switch (xNav.NodeType)
{



</div>
<span class='text_page_counter'>(88)</span><div class='page_container' data-page=88>

break;


case XPathNodeType.Comment:
sb.Append("Comment:");
sb.AppendLine(xNav.Value);
break;


case XPathNodeType.Element:
sb.Append("Element: ");
sb.AppendLine(xNav.Name);
break;


case XPathNodeType.Text:
sb.Append(" - Value:");
sb.AppendLine(xNav.Value);
break;


default:
break;
}


// Get attributes


if (xNav.HasAttributes)
{


xNav.MoveToFirstAttribute();
do



{


sb.Append(indentation);
sb.Append(" - Attribute:");
sb.Append(xNav.Name);


sb.Append(" - Value: ");
sb.AppendLine(xNav.Value);


} while (xNav.MoveToNextAttribute());
xNav.MoveToParent();


}


if (xNav.HasChildren)
{


xNav.MoveToFirstChild();
do


</div>
<span class='text_page_counter'>(89)</span><div class='page_container' data-page=89>

sb.Append(GetXPathNavContent(xNav, level + 1));
} while (xNav.MoveToNext());
xNav.MoveToParent();


}


return sb.ToString();
}


}


}


<i><b>4.3.3. Sử dụng XMLtextreader </b></i>


Đây là cách thức đơn giản nhất để đọc nội dung file XML. Tốc độ và sử
dụng tài nguyên là ưu điểm của XMLTextReader. Tuy nhiên với
XMLTextReader, các node chỉ được duyệt một lần, tuần tự từ trên xuống dưới.
Ta không thể di chuyển đến các node cha, node anh em … một cách tự do như
với XPathNavigator và XMLDocument.


Đối với XMLTextReader, khơng có khái niệm về node cha, node con, mà
được thay bằng khái niệm về Element


Name : Tên của element.


Value : Giá trị của element.


Read(): Duyệt node tuần tự, trả về false khi kết thúc.
MoveToFirstAttribute(): Chuyển đến thuộc tính đầu tiên.


MoveToNextAttribute(): Chuyển đến thuộc tính tiếp theo


MoveToElement(): Chuyển đến element tương ứng với thuộc tính hiện tại


using System;


using System.Collections.Generic;
using System.LINQ;


using System.Text;


using System.XML;


using System.XML.XPath;
using System.Data


namespace Demo3
{


class Program
{


</div>
<span class='text_page_counter'>(90)</span><div class='page_container' data-page=90>

{


string fileName = "DVDList.XML";
string content =


GetTextReaderContent(fileName);
}


private static string


GetTextReaderContent(string fileName)
{


// Create the reader


XMLTextReader reader = new
XMLTextReader(new FileStream(fileName,
FileMode.Open));



// Create string builder


StringBuilder sb = new StringBuilder();
while (reader.Read())


{


// Check node type


switch (reader.NodeType)
{


case XMLNodeType.XMLDeclaration:
sb.Append("Declaration:");
sb.Append(reader.Name);


sb.AppendLine(reader.Value);
break;


case XMLNodeType.Comment:
sb.Append("Comment:");


sb.AppendLine(reader.Value);
break;


case XMLNodeType.Element:
sb.Append("Element:");


sb.AppendLine(reader.Name);
break;



case XMLNodeType.Text:


sb.Append(" - Value:");


sb.AppendLine(reader.Value);
break;


</div>
<span class='text_page_counter'>(91)</span><div class='page_container' data-page=91>

break;
}


// Check attributes


if (reader.AttributeCount > 0)
{


while


(reader.MoveToNextAttribute())
{


sb.Append(" - Attribute:");
sb.Append(reader.Name);
sb.Append(" - Value: ");
sb.AppendLine(reader.Value);
}


}
}



// Close reader
reader.Close();


return sb.ToString();
}


}
}


<b>Đọc nội dung bắt đầu từ Element cho trước </b>


Trong nhiều trường hợp ta muốn đọc và duyệt nội dung XML bắt đầu từ
một Element xác định. Ta có thể sử dụng phương thức ReadStartElement() của
XMLTextReader để thực hiện việc này. Ngoài ra sử dụng phương thức
ReadElementString() để đọc nội dung text của một Element đã chỉ định.


using System;


using System.Collections.Generic;
using System.LINQ;


using System.Text;
using System.XML;


using System.XML.XPath;
using System.Data;


namespace Demo3
{



class Program
{


</div>
<span class='text_page_counter'>(92)</span><div class='page_container' data-page=92>

{


string fileName = "DVDList.XML";
string content =


GetStartFroMSpecificElement(fileName);
}


private static string


GetStartFroMSpecificElement(string fileName)
{


// Create reader


XMLTextReader reader =
new XMLTextReader(new
FileStream(fileName, FileMode.Open));


// Start read at DVDList element
reader.ReadStartElement("DVDList");
StringBuilder sb = new StringBuilder();
while (reader.Read())


{


if (reader.Name.Equals("DVD") &&




reader.NodeType.Equals(XMLNodeType.Element))
{


reader.ReadStartElement("DVD");
// Write string content of


Element




sb.AppendLine(reader.ReadElementString("Title"));
sb.AppendLine(" . " +


reader.ReadElementString("Description"));
sb.AppendLine(" . " +
reader.ReadElementString("Price"));


sb.AppendLine();
}


}


reader.Close();


return sb.ToString();
}


</div>
<span class='text_page_counter'>(93)</span><div class='page_container' data-page=93>

<b>4.4. Ghi file XML bằng .NET </b>



Có 2 phương pháp được sử dụng để ghi dữ liệu dạng XML ra file:


- Sử dụng XMLDocument class: là phương pháp chủ yếu được dùng khi
ta muốn cập nhật (thêm, sửa, xóa) một node trên nội dung XML có sẵn.


- Sử dụng XMLTextWriter class: là phương pháp ghi dữ liệu trực tiếp ra
luồng sử dụng XMLTextWriter. Đây là phương pháp đơn giản để tạo nội dung
file XML.


<b>Các thuộc tính và phương thức cơ bản trong XMLTextWriter: </b>
Formating Định dạng hiển thị XML


Indentaion Khoảng cách thụt đầu dòng


WriteStartDocument() Tạo khai báo XML: <?XML version='1.0'
encoding='UTF-8'?>


WriteComment() Tạo comment
WriteStartElement() Tạo các node con


WriteAttributeString() Tạo thuộc tính của node
WriteValue() Tạo giá trị text cho node


WriteElementString() Tạo node và giá trị text đồng thời
WriteEndElement() Kết thúc tạo node


Ví dụ về tạo file XML bằng XMLTextWriter
using System;



using System.Collections.Generic;
using System.LINQ;


using System.Text;
using System.XML;


using System.XML.XPath;
using System.Data;


namespace Demo3
{


class Program
{


static void Main(string[] args)
{


XMLTextWriter XMLWriter = new


</div>
<span class='text_page_counter'>(94)</span><div class='page_container' data-page=94>

Formatting.Indented;


XMLWriter.Indentation = 4;


XMLWriter.WriteProcessingInstruction("XML",
"version='1.0' encoding='UTF-8'");


XMLWriter.WriteComment("Ngày " +
DateTime.Now.ToString());



XMLWriter.WriteStartElement("DVDList");


XMLWriter.WriteStartElement("DVD");
XMLWriter.WriteAttributeString("ID",
"1");




XMLWriter.WriteAttributeString("Category",
"Science");


// Film title


XMLWriter.WriteStartElement("Title");
XMLWriter.WriteValue("Tear of the Sun");
XMLWriter.WriteEndElement();


// Film description


XMLWriter.WriteStartElement("Description");
XMLWriter.WriteValue("The war in
Columbia");


XMLWriter.WriteEndElement();
// Film price


XMLWriter.WriteStartElement("Price");
XMLWriter.WriteValue("$40,000,000");
XMLWriter.WriteEndElement();



// Film stars


XMLWriter.WriteStartElement("Stars");


</div>
<span class='text_page_counter'>(95)</span><div class='page_container' data-page=95>

XMLWriter.WriteEndElement();


XMLWriter.WriteStartElement("Star");
XMLWriter.WriteValue("Monica Bellucci");
XMLWriter.WriteEndElement();


// End Film stars


XMLWriter.WriteEndElement();


// End the DVD id = 1


XMLWriter.WriteEndElement();


// End the DVDList


XMLWriter.WriteEndElement();


// Close the stream
XMLWriter.Close();
}


}
}



<b>4.5. XML VÀ DATASET </b>


Ta có thể đọc file XML đó lên và hiển thị dữ liệu vào gridview control.
Để đọc dữ liệu lên được cần sử dụng một đối tượng đó là DataSet chuyên biệt
xử lý dữ liệu.


Thiết kế 1 giao diện có 2 control sau: GridView; Button.


Nội dung của file products.XML được thể hiện như cấu trúc sau:
<?XML version="1.0" encoding="utf-8" ?>


</div>
<span class='text_page_counter'>(96)</span><div class='page_container' data-page=96>

<Product_id>1</Product_id>


<Product_name>Product 1</Product_name>
<Product_price>1000</Product_price>
</Product>


<Product>


<Product_id>2</Product_id>


<Product_name>Product 2</Product_name>
<Product_price>2000</Product_price>
</Product>


<Product>


<Product_id>3</Product_id>


<Product_name>Product 3</Product_name>


<Product_price>3000</Product_price>
</Product>


<Product>


<Product_id>4</Product_id>


<Product_name>Product 4</Product_name>
<Product_price>4000</Product_price>
</Product>


</Table>


Tạo một hàm có tên loadXML để cài đặt việc lấy dữ liệu này thông qua
dataset.


private void loadXML()
{


//string s = Server.MapPath("XML");
string fileName = "XMLproducts.XML";
XMLReader XMLFile;


XMLFile = XMLReader.Create(fileName, new
XMLReaderSettings());


DataSet ds = new DataSet();
ds.ReadXML(XMLFile);


dataGridView1.DataSource = ds.Tables[0];


//dataGridView1.DataBindings();


}


Gọi hàm loadXML tại sự kiện click của button để hiển thị dữ liệu cho
người dùng


</div>
<span class='text_page_counter'>(97)</span><div class='page_container' data-page=97>

e)


{


loadXML();
}


Kết quả thực hiện:


<b>TÀI LIỆU THAM KHẢO </b>


1. Benoit Marchal (2000), XML By Example. 1st Edition.
2. Website:


<i><b>Câu hỏi và bài tập: </b></i>


1. Trình bày các khơng gian tên xử lý tệp tin XML? Giải thích ý nghĩa của
các khơng gian tên đó?


</div>
<span class='text_page_counter'>(98)</span><div class='page_container' data-page=98>

<b>Chương 5 </b>
<b>LINQ </b>
<b>5.1. Giới Thiệu LINQ </b>



<i><b>5.1.1. Tổng quan LINQ </b></i>


LINQ (Language Intergrated Query) là một công nghệ trên nền tảng
.NET, cung cấp một giải pháp hợp nhất cho việc truy vấn dữ liệu, tích hợp cách
truy vấn theo cú pháp SQL vào ngơn ngữ lập trình (cụ thể như C# hay
VB.NET), áp dụng cho tất cả các dạng dữ liệu từ đối tượng cho đến CSDL quan
hệ và cả XML …


Việc xử lý thông tin và các thao tác trên dữ liệu là 1 nhiệm vụ hết sức
quan trọng, bởi lẽ CSDL có thể nói là cốt lõi (Core) của tất cả các ứng dụng, và
một một trong những trở ngại chính mà các nhà phát triển ứng dụng (Developer)
ln đối mặt đó là sự khác biệc giữa ngôn ngữ lập trình hướng đối tượng và
ngôn ngữ truy vấn dữ liệu, càng phức tạp hơn nếu CSDL là XML ….


Hiện nay có thể có một số cơng nghệ hổ trợ việc truy vấn dữ liệu nhưng
việc sử dụng hết sức rờm rà, phải qua nhiều thao tác để trả về một kết quả, và
bản chất là phải truyền vào những câu lệnh SQL, điều này làm cho thời gian
phát triển ứng dụng kéo dài bởi lẽ người lập trình phải tốn thêm khá nhiều thời
gian để tiếp cận cách sử dụng, hơn nữa việc xử lý nếu không hay sẽ dể gây chết
ứng dụng. Mặc khác, khi các công nghệ này trả về một kết quả sẽ là một
DataTable hay DataSet mà không phải là một đối tượng hay một danh sách đối
tượng, điều đó sẽ gây khó khăn trong việc quản lý.


Nhìn thấy được không chỉ là những vấn đề trên mà còn nhiều vấn đề khác,
Microsoft đã cho ra đời cơng nghệ LINQ, nhằm giải quyết những vấn đề khó
khăn trên dữ liệu mà chúng ta đã và đang gặp phải.


Ngơn ngữ tích hợp truy vấn (Language Integrated Query: LINQ) được
Microsoft thêm vào .NET Framework để làm việc với dữ liệu (ví dụ: danh sách
đối tượng trong bộ nhớ, database, XML) theo cách đơn giản và trực quan nhất.


LINQ cung cấp tầng lập trình trừu tượng giữa các ngôn ngữ .NET với dữ liệu.


</div>
<span class='text_page_counter'>(99)</span><div class='page_container' data-page=99>

<i>LINQ gồm các loại sau: </i>


- LINQ to Objects: Làm việc với dữ liệu trên bộ nhớ (thường là các danh
sách kế thừa interface IEnumerable) sử dụng cú pháp ngôn ngữ LINQ.


- LINQ to XML: Làm việc với dữ liệu XML sử dụng cú pháp ngôn ngữ
LINQ.


- LINQ to Entities: Làm việc với Entity Framework.
- LINQ to SQL: Làm việc với SQL SERVER.


- LINQ to Datasets: Một kỹ thuật cho phép sử dụng LINQ trong một ứng
dụng dựa trên DataSet mà không cần viết lại sử dụng LINQ to SQL.


- PLINQ: Hỗ trợ sử dụng LINQ trong lập trình song song.
Các lợi ích khi sử dụng LINQ:


<b>Chỉ cần nhớ một ngôn ngữ truy vấn </b>


Đây là lợi thế đầu tiên mà LINQ cung cấp cho các lập trình viên. Một khi
bạn đã học được các toán tử truy vấn chuẩn của LINQ được cung cấp trong ngôn
ngữ C# hoặc VB.NET, bạn có thể truy cập bất kỳ dữ liệu nào mà LINQ hỗ trợ
mà không cần phải học cú pháp ngơn ngữ truy vấn dữ liệu đó.


<b>Kiểm tra kiểu dữ liệu và tên lúc biên dịch </b>


Các truy vấn LINQ được kiểm tra kiểu dữ liệu và tên lúc biên dịch, giảm
thiểu các lỗi xuất hiện lúc thực thi. Nhiều ngôn ngữ-T-SQL chẳng hạn, nhúng


câu truy vấn vào chuỗi. Điều này làm trình biên dịch khó phát hiện ra lỗi và lỗi
có thể xảy ra lúc thực thi. Nhiều lỗi về kiểu dữ liệu và thiếu kiểu dữ liệu cho
các trường dữ liệu sẽ được phát hiện lúc biên dịch và sẽ được chỉnh sửa tại thời
điểm đó.


<b>Dễ đọc mã </b>


Cú pháp của LINQ rất đơn giản do nó đã xóa bỏ đi các các đoạn mã vòng
lặp, sắp xếp, gom nhóm, điều kiện phức tạp.


<b>Trên 50 tốn tử truy vấn chuẩn </b>


Các toán tử truy vấn chuẩn được xây dựng sẵn cho phép dễ dàng thực
hiện các cơng việc như gom nhóm, sắp xếp, liên kết, tập hợp, lọc, hoặc lấy
dữ liệu.


</div>
<span class='text_page_counter'>(100)</span><div class='page_container' data-page=100>

<b>Bảng 5.1. Các loại toán tử truy vấn thường dùng </b>


<b>Loại toán tử </b> <b>Tên các toán tử truy vấn chuẩn </b>


Aggregation Aggregate, Average, Count, LongCount, Max, Min, Sum
Conversion AsEnumerable, Cast, OfType, ToArray, ToDictionary, ToList,


ToLookup


Element DefaultIfEmpty, ElementAt, ElementAtOrDefault, First,
FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault
Equality SequenceEqual


Generation Empty, Range, Repeat


Grouping GroupBy, ToLookup
Joining GroupJoin, Join
Merging Zip


Ordering OrderBy, ThenBy, OrderByDescending, ThenByDescending,
Reverse


Projection Select, SelectMany


Partitioning Skip, SkipWhile, Take, TakeWhile
Quantifiers All, Any, Contains


Restriction Distinct, Where


Set Concat, Except, Intersect, Union


Nhiều tốn tử truy vấn có thể được tìm thấy trong các ngôn ngữ truy vấn cơ
sở dữ liệu. Nếu bạn đã từng làm việc với các ngôn ngữ truy vấn dữ liệu thì bạn có
thể dễ dàng phán đốn ra chức năng của các tốn tử đó. Tuy nhiên cũng có vài
tồn tử hồn tồn mới, được thêm vào để làm việc với dữ liệu để làm đơn giản
hóa các đoạn mã truyền thống vốn phức tạp và dài dòng vào trong 1 dòng lệnh.


 Kiến trúc mở và có thể mở rộng


LINQ được thiết kế có khả năng mở rộng. Có nghĩa là có thể thêm vào
các toán tử khi cần thiết.


<i><b>5.1.2. Giới thiệu về các truy vấn LINQ </b></i>


</div>
<span class='text_page_counter'>(101)</span><div class='page_container' data-page=101>

Ba thành phần cơ bản của một biểu thức LINQ gồm:



 Có được các dữ liệu nguồn.


 Tạo các truy vấn.


 Thực hiện các truy vấn.


Ví dụ trong mã nguồn sau đây cho thấy cách thức hoạt động của ba thành
phần trong một truy vấn LINQ hoạt động như thế nào. Ví dụ sử dụng một mảng
số nguyên như là một sự thay thế cho nguồn dữ liệu.


class IntroToLINQ
{


static void Main()
{


int[] numbers = new int[7] {0,1,2,3,4,5,6};


var numQuery = from num in numbers where (num % 2)
== 0 select num;




foreach (int num in numQuery)
{


Console.Write("{0,1} ", num);
}



}
}


Minh họa sau đây cho thấy các hoạt động truy vấn tìm kiếm được hoàn
tất. Trong LINQ việc thực hiện các truy vấn riêng biệt từ bản thân câu truy vấn.
Nói cách khác bạn khơng lấy ra bất kỳ dữ liệu nào bằng cách tạo ra một biến
truy vấn.


</div>
<span class='text_page_counter'>(102)</span><div class='page_container' data-page=102>

<i>5.1.2.1. Các nguồn dữ liệu</i>


Trong ví dụ trước vì dữ liệu là một mảng, nó hồn tồn hỗ trợ đặc điểm
chung giao diện IEnumerable <T>. Điều này có nghĩa thực tế nó có thể được
truy vấn với LINQ. Một truy vấn được thực hiện trong một câu lệnh foreach và
foreach yêu cầu IEnumerable hay IEnumerable(T). Loại có hỗ trợ
IEnumerable(T) hoặc một giao diện như IQueryable(T) được gọi là các loại
queryable. Một loại queryable không yêu cầu phải sửa đổi hay xử lý đặc biệt để
phục vụ một LINQ nguồn dữ liệu. Nếu các nguồn dữ liệu không phải là đã có
trong bộ nhớ như là một loại queryable, một nhà cung cấp LINQ phải đại diện
cho nó như vậy. Ví dụ, LINQ to XML một tài liệu XML vào một queryable
XElement:


foreach (int num in numQuery)
{


Console.Write("{0,1} ", num);
}


Với LINQ to SQL trước tiên bạn tạo một đối tượng quan hệ được ánh xạ
vào lúc thiết kế cái này được làm thủ cơng hoặc bằng cách sử dụng trình thiết kế
đối tượng quan hệ (O/R Designer). Ta viết các câu truy vấn của bạn dựa trên đối


tượng và thi hành LINQ to SQL để xử lý các giao tiếp với cơ sở dữ liệu. Trong
ví dụ sau, Customer đại diện cho một bảng trong cơ sở dữ liệu, và
Table<Customer> hỗ trợ các đặc tính chung IQueryable<T> mà được bắt đầu từ
IEnumerable<T>.


// Create a data source from a SQL SERVER database.
// using System.Data.LINQ;


DataContext db


= new DataContext(@"c:\northwind\northwnd.mdf");
<i>5.1.2.2. Truy vấn </i>


</div>
<span class='text_page_counter'>(103)</span><div class='page_container' data-page=103>

LINQ, các biến truy vấn tựu nó khơnghành động và trả về khơng có dữ liệu. Nó
chỉ chứa đựng thơng tin đó là u cầu từ kết quả trả về khi câu truy vấn được
thực hiện tại một số điểm sau.


 Thực thi truy vấn;


 Hoãn thực thi.


Cũng giống như trạng thái trước đây, biến truy vấn tự nó chỉ chứa các
lệnh truy vấn. Hiện nay sự thực thi của các truy vấn là hoãn lại đến tận khi bạn
nhắc lại đối với biến truy vấn trong câu lệnh foreach. Cái này làm cơ sở để quy
cho hoãn thực thi và là cái điển hình trong ví dụ sau:


foreach (int num in numQuery)
{


Console.Write("{0,1} ", num);


}


Câu lệnh foreach là nơi các kết quả truy vấn được trả về ví dụ các truy
vấn trước đó biến num được lặp và nắm dữ mỗi giá trị trong trình tự trả về. Bởi
các biến truy vấn tự nó khơng bao giờ chứa kết quả truy vấn, bạn có thể thực
hiện nó thường xuyên như bạn muốn. Ví dụ bạn đang có một cơ sở dữ liệu mà
đang được cập nhập liên tục bởi một ứng dụng riêng biệt. Trong ứng dụng của
bạn, bạn có thể tạo một truy vấn để lấy ra dữ liệu mới nhất và bạn có thể thi
hành nó một cách liên tục tại một khoảng thời gian để lấy kết quả mỗi lần.


 Thực thi bắt buộc tức thời:


Truy vấn mà sự kết hợp thực hiện các chức năng trên một loạt các phần tử
nguồn đầu tiên phải lặp đi lặp lại trên những nhần tử. Ví dụ như các truy vấn
Count, Max, Average, và First. Những thực thi mà khơng có một câu lệnh
foreach nào rõ ràng bởi vì các truy vấn tự nó phải sử dụng foreach để trả về là
một kết quả. Cũng lưu ý rằng các loại truy vấn trả lại một giá trị, không phải là
một tập IEnumerable. Các truy vấn sau đây sẽ trả về một số lượng các số trong
mảng nguồn:


var evenNumQuery = from num in numbers
where (num % 2) == 0
select num;


</div>
<span class='text_page_counter'>(104)</span><div class='page_container' data-page=104>

select num).ToList();
// or like this:


// numQuery3 is still an int[]


var numQuery3 = (from num in numbers


where (num % 2) == 0
select num).ToArray();
<b>5.2. Kiến trúc LINQ </b>


<b>Hình 5.2. Kiến trúc LINQ trong .NET Framework 3.5 </b>


- Từ sơ đồ trên chúng ta thấy rõ rằng ứng dụng VB.NET hay C# dùng
LINQ để gọi xuống CSDL và chuyển thành SQL sau đó trả kết quả về là tập
hợp, hay đối.


<b>5.3. Sử dụng LINQ với object </b>


LINQ to Objects là thuật ngữ dùng để đề cập đến việc sử dụng các truy
vấn LINQ với bất kỳ tập hợp Ienumerable hay Ienumerable (T) mà không cần sử
dụng một nhà cung cấp hay API như LINQ to SQL hay LINQ to XML. Ta có
thể sử dụng LINQ để truy vấn bất kỳ bộ sưu tập enumerable như: List(T), Array,
hoặc Dictionary (Tkey, Tvalue). Các tập hợp có thể được người dùng xác định
hoặc có thể được trả lại bởi một .NET Framework API.


</div>
<span class='text_page_counter'>(105)</span><div class='page_container' data-page=105>

lặp foreach phức tạp theo lý thuyết để xác định rằng làm thế nào truy xuất được
dữ liệu từ một tập hợp. Trong LINQ đưa ra cách tiếp cận mới, ta có thể viết
đoạn mã nguồn có tính mơ tả những gì ta muốn truy xuất. Ngoài ra, các truy vấn
LINQ cung cấp ba sự tiện lợi hơn các vòng lặp foreach truyền thống, đó là:


 Ngắn gọn và dễ đọc đặc biệt là trong trường hợp có nhiều điều kiện lọc;


 Cung cấp bộ lọc mạnh mẽ, sắp xếp và khả năng gom nhóm với đoạn mã
ứng dụng nhỏ nhất;


 Có thể được chuyển đến các nguồn dữ liệu khác với một vài hoặc


khơng có sửa đổi, bổ sung.


Sử dụng LINQ to Objects, ta có thể thực hiện các hoạt động phức tạp hơn
trên cơ sở dữ liệu: Truy vấn tới một ArrayLisst LINQ; Đếm sự xuất hiện của
một từ trong một chuỗi (LINQ); Truy vấn cho câu có chứa một bộ từ, các ký tự
trong một String (LINQ); Kết hợp LINQ truy vấn với các biểu thức chính quy;
Tìm sự khác biệt giữa hai danh sách…


<b>5.4. Sử dụng LINQ với ADO.NET </b>


Ngơn ngữ tích hợp truy vấn LINQ định nghĩa một tập các toán tử truy vấn
chuẩn mà lập trình viên có thể sử dụng trên nền tảng .NET Framework. Các toán
tử truy vấn chuẩn cho phép vận hành dự án, lọc và đi ngang bộ nhớ trong tập
hợp hoặc một cơ sở dữ liệu trong bảng. Lưu ý rằng các truy vấn LINQ được thể
hiện trong ngôn ngữ lập trình của riêng mình, và khơng như chuỗi ký tự nhúng
vào đoạn mã ứng dụng. Đây là một thay đổi đáng kể từ các ứng dụng đã được
viết trên các phiên bản cũ của .NET Framework. Viết truy vấn từ bên trong ngơn
ngữ lập trình cung cấp một vài lợi thế chủ chốt, được đơn giản hóa bằng cách
loại bỏ các truy vấn cần phải sử dụng một ngôn ngữ truy vấn riêng biệt. Trong bộ
công cụ Visual Studio của Microsoft, LINQ cũng cho phép tận dụng lợi thế của
quá trình kiểm tra tại thời điểm biên dịch, loại tĩnh và trình hỗ trợ thơng minh.


LINQ được tích hợp vào nhiều khía cạnh khác nhau của việc truy cập dữ
liệu trong .NET Framework, bao gồm cả việc ngắt kết nối DataSet với mơ hình
lập trình và hiện tại giản đồ cơ sở dữ liệu SQL SERVER. Phần này để mô tả
trong LINQ to ADO.NET.


</div>
<span class='text_page_counter'>(106)</span><div class='page_container' data-page=106>

<b>Hình 5.3. LINQ với ADO.NET </b>
<b>5.5. Sử dụng LINQ với XML </b>



LINQ to XML cung cấp giao diện lập trình XML mà đòn bẩy là .NET
Language-Intergrated Query (LINQ) Framework. LINQ to XML sử dụng ngôn
ngữ mới nhất của .NET Framework và được so sánh, thiết kế lại với giao diện
lập trình XML Document Object Model (DOM)


LINQ to XML bao gồm các phương pháp khác nhau cho phép có thể thay
đổi sơ đồ XML trực tiếp, ta có thể thâm các yếu tốt, xóa các yếu tố, thayd dổi
nội dung của một yếu tốt đó và thêm các thuộc tính… Giao diện lập trình được
mơ tả trong sơ đồ Modifying XML.


<b>TÀI LIỆU THAM KHẢO </b>
1. Website:


<i><b>Câu hỏi và bài tập: </b></i>


</div>
<span class='text_page_counter'>(107)</span><div class='page_container' data-page=107>

<b>MỤC LỤC </b>


<b>Chương 1. LẬP TRÌNH CƠ SỞ DỮ LIỆU VỚI ADO.NET ... 5 </b>


1.1. Tổng quan về lập trình với cơ sở dữ liệu ... 5


<i>1.1.1. Giới thiệu ... 5 </i>


<i>1.1.2. Quá trình phát triển lập trình cơ sở dữ liệu ... 6 </i>


1.2. Kiến trúc ADO.NET ... 11


1.3. Làm việc với các đối tượng của ADO.NET ... 13


<i>1.3.1. Đối tượng Connection ... 13 </i>



<i>1.3.2. Đối tượng Command ... 15 </i>


<i>1.3.3. Đối tượng DataReader ... 17 </i>


<i>1.3.4. Đối tượng DataSet và DataAdapter ... 20 </i>


<b>Chương 2. LẬP TRÌNH TRONG HỆ QUẢN TRỊ DỮ LIỆU ... 27 </b>


2.1. Tổng quan về hệ quản trị dữ liệu SQL SERVER ... 27


<i>2.1.1. Giới thiệu hệ quản trị dữ liệu SQL SERVER ... 27 </i>


<i>2.1.2. Các thành phần chính của MS SQL SERVER ... 27 </i>


<i>2.1.3. Các đối tượng trong MS SQL SERVER ... 28 </i>


2.2. Tổng quan về lập trình trong hệ quản trị dữ liệu ... 30


<i>2.2.1. Ngơn ngữ truy vấn có cấu trúc (SQL) ... 30 </i>


<i>2.2.2. Một số câu lệnh SQL thường dùng ... 31 </i>


2.3. Thủ tục (Stored procedure) ... 34


<i>2.3.1. Các khái niệm ... 34 </i>


<i>2.3.2. Các loại thủ tục ... 35 </i>


<i>2.3.3. Tạo thủ tục lưu trữ ... 36 </i>



<i>2.3.4. Sử dụng biến trong thủ tục ... 38 </i>


<i>2.3.5. Giá trị trả về của tham số trong thủ tục lưu trữ ... 39 </i>


<i>2.3.6. Tham số với giá trị mặc định ... 40 </i>


<i>2.3.7. Sửa đổi thủ tục ... 41 </i>


<i>2.3.8. Xoá thủ tục ... 41 </i>


<i>2.3.9. Thực thi một thủ tục lưu trữ ... 41 </i>


2.4. Hàm người dùng định nghĩa (Functions) ... 43


<i>2.4.1. Định nghĩa và sử dụng hàm ... 44 </i>


</div>
<span class='text_page_counter'>(108)</span><div class='page_container' data-page=108>

2.5. Trigger ... 47


<i>2.5.1. Định nghĩa trigger ... 48 </i>


<i>2.5.2. Sử dụng mênh đề if update trong trigger ... 51 </i>


<i>2.5.3. Rollback transaction và trigger ... 53 </i>


<i>2.5.4. Sử dụng trigger trong trường hợp insert, update và delete có tác động </i>
<i>đến nhiều dịng dữ liệu ... 54 </i>


<b>Chương 3. THIẾT KẾ ỨNG DỤNG THEO MƠ HÌNH NHIỀU LỚP ... 61 </b>



3.1. Giới thiệu mơ hình nhiều lớp ... 61


3.2. Kiến trúc mơ hình ... 61


3.3. Lớp trình diễn dữ liệu (Presentation Layers – PL) ... 62


3.4. Lớp xử lý logic (Business Logic Layer – BLL) ... 63


3.5. Lớp truy cập dữ liệu (Data Access Layer – DAL) ... 63


3.6. Ưu việt và hạn chế của mơ hình lập trình nhiều lớp ... 75


3.7. Mơ hình MVC (Model – View – Controller) ... 75


<b>Chương 4. LÀM VIỆC VỚI TẬP TIN XML ... 79 </b>


4.1. Giới thiệu XML ... 79


4.2. Các không gian tên xử lý XML trong .NET ... 79


4.3. Đọc file XML bằng .NET ... 81


<i>4.3.1. Sử dụng XMLNodeList ... 84 </i>


<i>4.3.2. Sử dụng xPathNavigator ... 86 </i>


<i>4.3.3. Sử dụng XMLtextreader ... 89 </i>


4.4. Ghi file XML bằng .NET ... 93



4.5. XML và dataset ... 95


<b>Chương 5. LINQ ... 98 </b>


5.1. Giới Thiệu LINQ ... 98


<i>5.1.1. Tổng quan LINQ ... 98 </i>


<i>5.1.2. Giới thiệu về các truy vấn LINQ ... 100 </i>


5.2. Kiến trúc LINQ ... 104


5.3. Sử dụng LINQ với Object ... 104


5.4. Sử dụng LINQ với ADO.NET ... 105


</div>

<!--links-->
Tài liệu bai11. Cac thao tac voi co so du lieu quan he
  • 13
  • 926
  • 1
  • ×