Hệ thống các lớp ADO.NET được chia thành hai dạng: các lớp kết nối (connected classes) và các lớp phi kết nối (disconnected classes) như hình dưới:

Trong phần này chúng ta sẽ tìm hiểu các lớp phi kết nối với hai lớp quan trọng nhất là DataTableDataSet. Gọi chúng là các lớp phi kết nối vì chủ yếu làm việc với dữ liệu lưu trữ bộ nhớ trong và không cần kết nối đến Data Store (phải dùng đến các lớp kết nối hay các lớp nhà cung cấp (provider classes)). Các lớp phi kết nối được thực thi trong assembly System.Data.dll và thuộc namespace System.Data.

Lớp DataTable

Lớp DataTable thể hiện dữ liệu dạng bảng gồm các cột được tạo bởi lớp DataColumn và các hàng dữ liệu được thêm vào bảng bởi lớp DataRow. Đoạn mã sau minh hoạ cách tạo một bảng tên Students chứa thông tin về cách sinh viên như sau:

Mã VB


' Tạo một DataTable tên Students

Dim students As New DataTable("Students")

Mã C#


// Tạo một DataTable tên Students

DataTable students = new DataTable ("Students");

Đoạn mã trên tạo ra một bảng rỗng và có thuộc tính TableName được gán giá trị là Students.

Thêm cột hay tạo lược đồ (schema) cho bảng với lớp DataColumn

Một DataTable chỉ có ích khi nó có một lược đồ được tạo bằng đối tượng DataColumn và thiết lập một vài ràng buộc cho mỗi cột. Các ràng buộc này duy trì tính toàn vẹn dữ liệu bằng cách hạn chế dữ liệu nhập vào cột. Đoạn mã sau minh hoạ cách thêm các cột IDName vào bảng Students:

Mã VB


Dim id As New DataColumn("ID")

id.DataType = GetType(Integer)

id.Unique = True

id.AllowDBNull = False

students.Columns.Add(id)

Dim name As New DataColumn("Name")

name.DataType = GetType(String)

name.MaxLength = 20;

name.AllowDBNull = True

students.Columns.Add(name)

Mã C#


DataColumn id = new DataColumn ("ID");

id.DataType = typeof (int);

id.Unique = true;

id.AllowNull = false;

students.Columns.Add (id);

DataColumn name = new DataColumn ("Name");

name.DataType = typeof (string);

name.MaxLength = 20;

name.AllowNull = true;

students.Columns.Add (name);

Lớp DataColumn có một số thuộc tính sau:

Thuộc tính Chức năng
DataType Xác định kiểu dữ liệu cho cột. Mặc định là kiểu chuỗi (string).
Unique Xác định tính duy nhất cho giá trị của cột nếu gán giá trị true và ngược lại khi gán giá trị false. Mặc định là false.
AllowNull Cho phép giá trị của cột null khi gán giá trị true và ngược lại khi gán giá trị false. Mặc định là true.
Caption Tiêu đề cột. Mặc định là giá trị thuộc tính ColumnName được chuyển đến hàm constructor.
MaxLength Số kí tự tối đa của một chuỗi. Giá trị mặc định là -1.

 

Khi đã tạo các cột, việc tiếp theo là xác định cột (hay nhóm cột) làm khoá chính (primary key) để xác định tính duy nhất cho mỗi hàng với thuộc tính PrimaryKey của DataTable. Thuộc tính PrimaryKey phải được gán đến một mảng các đối tượng DataColumn để chứa các khoá kết hợp. Đoạn mã sau minh hoạ cách lấy cột ID làm khoá chính cho bảng students:

Mã VB


students.PrimaryKey = new DataColumn(){id}

Mã C#


students.PrimaryKey = new DataColumn[]{id};

Thiết lập tăng giá trị (số) tự động cho cột khoá chính

Chúng ta có thể thiết lập chế độ tăng giá trị số tự động cho cột khoá chính bằng các thuộc tính AutoIncrement, AutoIncrementSeed, và AutoIncrementStep của đối tượng DataColumn như mô tả ở bảng dưới đây:

Thuộc tính Chức năng
AutoIncrement Cho phép giá trị số trong cột được tăng tự động mỗi khi một hàng mới được thêm vào bảng.
AutoIncrementSeed Giá trị của số đầu tiên muốn tăng tự động. Giá trị mặc định được khuyên là -1.
AutoIncrementStep Giá trị muốn tăng mỗi khi một hàng mới được thêm vào. Mặc định được khuyên là -1.

 

* Giá trị của AutoIncrementSeedAutoIncrementStep luôn luôn được gán đến giá trị -1 để tránh xung đột giá trị nhận được từ database server vì database không có số âm.

Thêm các hàng dữ liệu vào bảng với đối tượng DataRow

DataTable chứa thuộc tính Rows kiểu DataRowCollection chứa các đối tượng DataRow. DataRowCollection chứa phương thức Add với nhiều phiên bản (quá tải) có thể nhận tham số là một đối tượng DataRow, hay một mảng các đối tượng DataRow, hay các giá trị của một hàng. Bên cạnh Add, DataRowCollection còn chứa các phương thức sau:

Phương thức Chức năng
ImportDataRow Thêm một đối tượng DataRow đã được chỉnh sửa vào bảng và vẫn giữ nguyên các trạng thái và các thiết lập trước đó.
Load Cập nhật đối tượng DataRow hiện tại hay thêm đối tượng DataRow mới.
LoadDataRow Phát sinh một hàng với tham số là một mảng các đối tượng DataRow và một giá trị kiểu liệt kê LoadOption (với các thành phần chi tiết ở bảng dưới).

 

Các thành phần hay thành viên của LoadOption (chú ý các khái niệm phiên bản (version) hay trạng thái (state) hàng sẽ được đề cập chi tiết ở các phần sau)

Thành viên Chức năng
OverwriteChanges Thay đổi phiên bản hàng hiện tại và phiên bản hàng gốc và thay đổi trạng thái hàng đến Unchanged. Hàng mới có trạng thái là Unchanged.
PreserveChanges (mặc định) Thay đổi phiên bản hàng gốc nhưng không thay đổi phiên bản hàng hiện tại. Hàng mới có trạng thái là Unchanged.
Upsert Thay đổi phiên bản hàng hiện tại nhưng không thay đổi phiên bản hàng gốc. Hàng mới có trạng thái là Added. Các hàng có trạng thái là Unchanged và phiên bản hàng hiện tại và hàng gốc giống nhau thì vẫn giữ nguyên là Unchanged, ngược lại nếu hai phiên bản khác nhau thì trạng thái đổi thành Modified.

 

Đoạn mã sau minh hoạ cách thêm hàng mới vào bảng Students

Mã VB


'thêm hàng mới bằng cách tạo DataRow đầu tiên

Dim newStudent As DataRow = student.NewRow()

newStudent ("ID") = 123

newStudent ("Make") = "Minh"

students.Rows.Add(newStudent)

'thêm hàng mới bằng cách chuyển giá trị trực tiếp

students.Rows.Add(124, "Dung")

'Cập nhật lại student có ID là 124 bằng LoadDataRow

students.LoadDataRow(new object() { 124, "Long"},LoadOption.OverwriteChanges)

Mã C#


//thêm hàng mới bằng cách tạo DataRow đầu tiên

DataRow newStudent = student.NewRow();

newStudent ["ID"] = 123  ;

newStudent ["Make"] = "Minh"  ;

students.Rows.Add(newStudent)  ;

//thêm hàng mới bằng cách chuyển giá trị trực tiếp

students.Rows.Add(124, "Dung");

//Cập nhật lại student có ID là 124 bằng LoadDataRow

students.LoadDataRow(new object[] { 124, "Long"},LoadOption.OverwriteChanges);

Xem trạng thái (state) của một đối tượng DataRow với DataRowState

Chúng ta có thể xem trạng thái hiện tại của một hàng với thuộc tính RowState có giá trị trả về là giá trị liệt kê DataRowState với các thành viên như sau:

Thành viên Chức năng
Detached Hàng được tạo nhưng không được thêm đến bảng
Added Hàng được tạo và được thêm đến bảng
Unchanged Hàng không thay đổi kể từ lần gọi cuối cùng phương thức AcceptChanges. Khi AcceptChanged được gọi, hàng sẽ chuyển đến trạng thái Unchanged.
Modified Hàng thay đổi kể từ lần gọi cuối cùng phương thức AcceptChanges. Thêm hàng hay cập nhật hàng sẽ thay đổi trạng thái hàng đến Added. Hàng chỉ thay đổi trạng thái đến Modified nếu trạng thái trước đó của hàng là Unchanged.
Deleted Một hàng bị xoá bởi phương thức Delete của DataRow hay phương thức DataTable.DeleteRow.

 

Minh hoạ (mã VB) xem trạng thái hàng với thuộc tính RowState


Dim dr As DataRow = sv.NewRow() ' Rowstate: Detached

Dim rs1 As String = String.Format("Rowstate 1:{0}", dr.RowState)

dr("ID") = "1" 'Rowstate: Detached

Dim rs2 As String = String.Format("Rowstate 2:{0}", dr.RowState)

dr("Name") = "Peter"

sv.Rows.Add(dr) ' Rowstate: Added

Dim rs3 As String = String.Format("Rowstate 3:{0}", dr.RowState)

sv.Rows.Add("2", "Messi") 'Rowstate: Added

sv.AcceptChanges()'Rowstate: Unchanged

Dim rs4 As String = String.Format("Rowstate 4:{0}", dr.RowState)

dr("ID") = "3"'Rowstate: Modified

Dim rs5 As String = String.Format("Rowstate 5:{0}", dr.RowState)

sv.RejectChanges()'Rowstate: Unchanged

Dim rs6 As String = String.Format("Rowstate 6:{0}", dr.RowState)

dr.Delete()'Rowstate: Deleted

Dim rs7 As String = String.Format("Rowstate 7:{0}", dr.RowState)

Dim rs = rs1 + vbCrLf + rs2 + vbCrLf + rs3 + vbCrLf + rs4 + vbCrLf + rs5 + vbCrLf + rs6 + vbCrLf + rs7 + vbCrLf

MsgBox(rs)

Kết quả

Quản lý các bản sao dữ liệu bằng DataRowVersion

Khi hàng dữ liệu trong bảng được tạo, bảng có thể nắm giữ các phiên bản hàng là giá trị kiểu liệt kê DataRowVersion với các thành viên sau:

Thành viên Chức năng
Current Giá trị hiện tại của hàng dữ liệu ngay cả sau khi các thay đổi được thực hiện. Phiên bản này tồn tại trong tất cả các trường hợp ngoại trừ khi DataRowState bị xoá. Khi DataRowState bị xoá, một ngoại lệ sẽ phát sinh.
Default Nếu DataRowState là Added hay Modified, phiên bản mặc định là Current. Nếu DataRowState bị xoá, một ngoại lệ sẽ phát sinh. Nếu phương thức BeginEdit đã được thực thi, phiên bản là Proposed.
Original Giá trị ban đầu được đưa vào hàng dữ liệu hay giá trị tại thời điểm phương thức AcceptChanges cuối cùng được thực thi. Phiên bản này không tồn tại cho đến khi DataRowState trở thành Modified, Unchanged, hay Deleted. Nếu DataRowState bị xoá, thông tin này có thể được nhận lại. Nếu DataRowState là Added, ngoại lệ VersionNotFound sẽ phát sinh.
Proposed Giá trị tại thời điểm chỉnh sửa (editing) dữ liệu hàng. Nếu DataRowState bị xoá, một ngoại lệ sẽ phát sinh. Nếu phương thức BeginEdit không được thực thi hay thực thi ngầm bằng cách chỉnh sửa dữ liệu trên hàng ở trạng thái Detached thì ngoại lệ VersionNotFound sẽ phát sinh.

 

Đối tượng DataRow chứa phương thức HasVersion dùng để kiểm tra sự tồn tại của một phiên bản hàng dữ liệu cụ thể. Đoạn mã sau minh hoạ cách nhận thông tin về phiên bản của hàng dùng HasVersion và DataRowVersion:

Mã VB


Dim versionString As String

For Each versionString In [Enum].GetNames(GetType(DataRowVersion))

Dim version As DataRowVersion = CType([Enum].Parse(GetType(DataRowVersion), versionString), DataRowVersion)

If (row.HasVersion(version)) Then

retVal += String.Format( "Version: {0} Value: {1}" + vbCrLf,version, row(columnName, version))

Else

retVal += String.Format( "Version: {0} does not exist." +  VbCrLf, version)

End If

Next

Mã C#

foreach (string versionString in Enum.GetNames(typeof (DataRowVersion)))

{

DataRowVersion version = (

DataRowVersion)Enum.Parse(

typeof(DataRowVersion),versionString);


if (row.HasVersion(version))

{

retVal += string.Format(

"Version: {0} Value: {1} \r\n",

version, row[columnName, version]);

}

else

{

retVal += string.Format(

"Version: {0} does not exist.\r\n",

version);

}

}

Một vài phương thức quan trọng

Khi làm việc với DataTable, bên cạnh phương thức Add, chúng ta cũng gặp một số phương thức quan trọng khác như AcceptChanges, RejectChanges, Delete, Copy, Clone. Chi tiết các phương thức có thể mô tả như bảng  sau:

Phương thức Chức năng
AcceptChanges Thiết lập trạng thái hàng đến Unchanged.
RejectChanges Thiết lập trạng thái hàng đến trạng thái lần cuối cùng AcceptChanges được gọi.
SetAdded Thiết lập trạng thái hàng đến Added và sẽ bỏ qua phiên bản hàng Original. Phương thức chỉ thực thi khi đối tượng DataRow có trạng thái là Unchanges, ngược lại sẽ phát sinh ngoại lệ. Hữu ích khi giao tiếp giữa các data store khác nhau.
SetModified Thiết lập trạng thái hàng đến Modified và không thay đổi các phiên bản hàng Original hay Current. Phương thức chỉ thực thi khi đối tượng DataRow có trạng thái là Unchanges, ngược lại sẽ phát sinh ngoại lệ. Hữu ích khi giao tiếp giữa các data store khác nhau.
Deleted Thiết lập trạng thái hàng đến Deleted.
Copy Sao chép cả lược đồ và dữ liệu từ đối tượng DataTable.
Clone Chỉ sao chép lược đồ của đối tượng DataTable.
ImportRow Sao chép hàng dữ liệu từ một bảng đến một bảng khác có cùng lược đồ (schema).

 

Minh hoạ dùng AcceptChangesRejectChanges

Mã VB

students.Rows.Add("1", "Peter")

students.Rows.Add("2", "Ronaldo")

'cập nhật các hàng mới

st.AcceptChanges()

students.Rows.Add("3", "Messi")

'từ chối thêm hàng mới

st.RejectChanges()

Mã C#

students.Rows.Add("1", "Peter");

students.Rows.Add("2", "Ronaldo");

//cập nhật các hàng mới

students.AcceptChanges();

students.Rows.Add("3", "Messi");

//từ chối thêm hàng mới

students.RejectChanges();

Minh hoạ dùng Delete

Mã VB

students.Rows(1).Delete()'xoá hàng thứ hai

Mã C#

students.Rows(1).Delete(); //xoá hàng thứ hai

Minh hoạ dùng Copy

Mã VB

'sao chép dữ liệu và lược đồ từ bảng students đến bảng copyofStudentTable
Dim copyofStudentTable As DataTable = students.Copy()

Mã C#

//sao chép dữ liệu và lược đồ từ bảng students đến bảng copyofStudentTable
DataTable copyofStudentTable = students.Copy();

Minh hoạ dùng Clone và ImportRow

Mã VB

'sao chép lược đồ từ bảng students đến bảng cloneofStudentTable

Dim cloneofStudentTable As DataTable = students.Clone()

'sao chép hàng thứ 3 của students đến cloneofStudentTable

cloneofStudentTable.ImportRow(students.Rows(2))

Mã C#

//sao chép lược đồ từ bảng students đến bảng cloneofStudentTable

DataTable cloneofStudentTable = students.Clone();

//sao chép hàng thứ 3 của students đến cloneofStudentTable

cloneofStudentTable.ImportRow(students.Rows(2));

Sử dụng đối tượng DataView
Khi có các bảng dữ liệu (các đối tượng DataTable), chúng ta có thể sử dụng đối tượng DataView như là một cửa sổ để lưu trữ hay trích lọc dữ liệu từ bảng. Mỗi bảng có thể được gán nhiều DataView để xem dữ liệu theo những cách khác nhau mà không cần cập nhật đến database (như minh hoạ hình dưới).

Sắp xếp dữ liệu với thuộc tính Sort

Chúng ta có thể hiển thị dữ liệu từ bảng thông qua DataView theo thứ tự tăng dần (mặc định) hay giảm dần dựa vào một hay nhiều cột (cách nhau bởi dấu phẩy) bằng thuộc tính Sort của DataView. Sắp xếp tăng dần chúng ta dùng ASC và giảm dần dùng DESC. Đoạn mã sau sẽ minh hoạ cách chúng ta sắp xếp dữ liệu trong bảng Students thông qua một DataView (dv) theo thứ tự giảm dần dựa vào cột ID:

Mã VB


Dim dv As New DataView(students) ' tạo một DataView

Dim i

dv.Sort = "ID DESC" ' sắp giảm dần theo cột ID

' Hiển thị DataView

For i = 0 To dv.Count - 1

lst_data.Items.Add(dv(i)("ID") & "   " & dv(i)("Name"))

Next

Mã C#


DataView dv = new DataView(students);

// tạo một DataView

int i;

dv.Sort = "ID DESC"; // sắp giảm dần theo cột ID

// Hiển thị DataView

for (i = 0; i <= dv.Count - 1; i++) {

lst_data.Items.Add(dv(i)("ID") + "   " + dv(i)("Name"));

}

Chúng ta cũng có thể sắp xếp theo nhiều cột ví dụ tăng dần theo cột ID và giảm dần theo Name như sau:

Mã VB


Dim dv As New DataView(students) ' tạo một DataView

Dim i

dv.Sort = "ID ASC, Name DESC" ' sắp tăng dần theo cột ID và giảm dần theo Name

' Hiển thị DataView

For i = 0 To dv.Count - 1

lst_data.Items.Add(dv(i)("ID") & "   " & dv(i)("Name"))

Next

Mã C#


DataView dv = new DataView(students);

// tạo một DataView

int i;

dv.Sort = "ID ASC, Name DESC"; // sắp tăng dần theo cột ID và giảm dần theo Name

// Hiển thị DataView

for (i = 0; i <= dv.Count - 1; i++) {

lst_data.Items.Add(dv(i)("ID") + "   " + dv(i)("Name"));

}

Lọc dữ liệu với các thuộc tính RowFilter và RowStateFilter

Chúng ta có thể xem dữ liệu của DataTable bằng nhiều cách khác nhau với DataView thông qua các thuộc tính trích lọc dữ liệu RowFilter và RowStateFilter. Giá trị của RowFilter là một chuỗi giống lệnh WHERE trong ngôn ngữ truy vấn SQL nhưng không dùng từ “WHERE”. Đoạn mã sau minh hoạ cách dùng RowFilter để lọc ra những sinh viên có tên (Name) bắt đầu bằng chữ R trong bảng Students:

Mã VB


dv.RowFilter = "Name like 'R%'"

Mã C#


dv.RowFilter = "Name like 'R%'";

Bên cạnh dùng RowFilter, chúng ta có thể dùng RowStateFilter để lọc theo phiên bản (DataRowVersion) hay trạng thái hàng (DataRowState). RowStateFilter yêu cầu các giá trị là các thành viên của DataViewRowState (kiểu liệt kê):

Thành viên Chức năng
Added Nhận đối tượng DataRow có phiên bản Current và trạng thái là Added.
CurrentRows Nhận tất cả  đối tượng DataRow có phiên bản Current. Tương đương các thành viên Added, ModifiedCurrent và Unchanged .
Deleted Nhận đối tượng DataRow có phiên bản Original và trạng thái là Deleted.
ModifiedCurrent Nhận đối tượng DataRow có phiên bản Current và trạng thái là Modified.
ModifiedOriginal Nhận đối tượng DataRow có phiên bản Original và trạng thái là Modified.
None Xoá thuộc tính RowStateFilter.
OriginalRows Nhận đối tượng DataRow có phiên bản Original.
Unchanged Nhận đối tượng DataRow có trạng thái là Unchanged.

 

Đoạn mã sau minh hoạ lọc danh sách sinh viên trong bảng Students theo Name bắt đầu bằng chữ R và chỉ áp dụng cho những hàng có trạng thái là Deleted:

Mã VB


dv.RowFilter = "Name like 'R%'"

dv.RowStateFilter = DataViewRowState.Deleted

Mã C#


dv.RowFilter = "Name like 'R%'";

dv.RowStateFilter = DataViewRowState.Deleted;

Di chuyển dữ liệu từ một DataView của một DataTable đến một DataTable khác

Để di chuyển dữ liệu từ một DataView của một DataTable đến một DataTable khác chúng ta dùng phương thức ToTable của DataView. Cú pháp phương thức ToTable:

VB


Public Function ToTable(tableName as String, distinct as Boolean, ParamArray columnNames() as String) as System.Data.DataTable

C#


DataTable DataView.ToTable(string tableName, bool distinct, params string[] columnNames)

Tham số tablename là tên bảng đích, distinct được gán đến true tức là chỉ lọc những giá trị không trùng nhau, và tham số cuối cùng là danh sách các cột được di chuyển đến bảng mới. Đoạn mã sau minh hoạ việc chuyển dữ liệu từ DataView dv từ bảng Students đến bảng mới tên MyStudents

Mã VB


Dim mystudents as DataTable = dv.ToTable( "MyStudents", true, "ID", "Name")

Mã C#


DataTable mystudents = dv.ToTable( "MyStudents", true, "ID", "Name");