ADO.NET – Cơ bản về DataSet (Part 2/2): DataRelation và Constraint

[…]DataSet là một đối tượng có thể chứa nhiều DataTable cùng với mối liên hệ giữa chúng (relationship) và kể các ràng buộc (constraint) được lưu hoàn toàn trong bộ nhớ để làm việc offline. Qua bài viết này, bạn có thể hiểu cấu trúc của DataSet, DataTable cũng như nạp dữ liệu, tạo relation, constraint và thao tác dữ liệu trên các đối tượng dữ liệu này.[…]

Bài viết trước: Cơ bản DataSet (Part 1/2): Cấu trúc của DataSet và DataTable

Nội dung:

Data Relation trong DataSet

Primary Key trong DataTable

Data Constraint trong DataTable

Data Relation trong DataSet


Tạo DataRelation:

Khi bạn thêm các table vào DataSet thì giữa chúng chưa có relation nào. Để tạo ra một relation, bạn sử dụng property Relations của DataSet để thêm vào các đối tượng DataRelation. Ví dụ sau tạo ra một relation giữa hai table Group, User trong DataSet thông qua cột GroupID trong mỗi table với tên relation mà tôi đặt là Group_User.

DataSet dataSet = LoadData();

DataTable userTable = dataSet.Tables["User"];

DataTable groupTable = dataSet.Tables["Group"];

DataRelation relation=new DataRelation("Group_User",
        groupTable.Columns["GroupID"],
        userTable.Columns["GroupID"]);

dataSet.Relations.Add(relation);

Phương thức GetChildRows():

Sau khi có relation, ta có thể dùng phương thức instance DataRow.GetChildRows() để lấy về một mảng các DataRow trong bảng con của bảng hiện tại.

DataRow[] groupRows = groupTable.Select("GroupID='1'");

DataRow[] memberRows = groupRows[0].GetChildRows("Group_User");

foreach (var row in memberRows)
    Console.WriteLine(row["UserName"]);

Output:

Adon
Balrog
Bison
Cammy
ChunLi
Dan
DeeJay

Dòng lệnh đầu tiên của đoạn mã trên lấy về một mảng DataRow bằng phương thức DataTable.Select(string filterExpression) với tham số là một câu lệnh lọc (giống biểu thức sau từ khóa “where” trong SQL).

Dựa vào dữ liệu, ta biết mảng này thực chất chỉ chứa một phần tử, chính vì thế ta lấy phần tử đầu tiên của mảng groupRows và gọi phương thức GetChildRows(string relationName). Và kết quả in ra màn hình sẽ là những user nằm trong GroupID là 1, tức là “Member”.

Phương thức GetParentRow():

 

Ngược với GetChildRows(), phương thức GetParentRow() trả về một DataRow từ bảng cha của bảng hiện tại dựa vào relation giữa chúng. Ví dụ sau cho thấy GroupName của user có UserID là “8”:

DataRow[] childRows = userTable.Select("UserID='8'");

DataRow parentRow = childRows[0].GetParentRow("Group_User");

Console.WriteLine(parentRow["GroupName"]);

Output:

Admin

Primary Key trong DataTable


DataTable có thể dùng một hoặc nhiều DataColumn để tạo ra một Primary Key. Primary Key là định danh phân biệt các DataRow và tránh trùng lặp dữ liệu. Dựa vào PrimaryKey, bạn mới có thể dùng phương thức Find() của DataRowCollection.

Đoạn code bên dưới sẽ tìm và trả về dòng dữ liệu với UserID là “1” trong table User:

DataColumn[] primaryKeys=new DataColumn[] {  table.Columns["UserID"] };

table.PrimaryKey = primaryKeys;

DataRow row = table.Rows.Find("1");

Console.WriteLine(row["UserName"]);

// Ouput: Adon

Data Constraint trong DataTable


Constraint là các “luật lệ” mà bạn có thể đặt cho DataColumn nhằm hạn chế và đảm bảo một vài quy tắc nào đó. Có hai loại constraint mà bạn có thể sử dụng:

–       UniqueConstraint: Các giá trị của cột phải là unique (duy nhất).

–       ForeignKeyConstraint: Duy trì liên kết giữa các DataTable trong DataSet.

Hai lớp này đều thừa kế từ lớp abstract Constraint:

UniqueConstraint:

DataTable userTable = dataSet.Tables["User"];
Constraint constraint=new UniqueConstraint(userTable.Columns["UserID"],true);
userTable.Constraints.Add(constraint);

Ví dụ trên sẽ tạo constraint cho cột UserID của table User. Tham số thứ hai của constructor UniqueConstraint chỉ ra cột được sử dụng có phải là primary key không. Vì tôi đặt là true, cột UserID này sẽ trở thành primary key của table này. Bạn có thể đặt thêm UniqueConstraint này cho bất kì cột nào muốn bảo đảm giữ liệu không trùng nhau.

Việc đặt constraint như trên tương đương với việc bạn gán property DataColumn.Unique = true. Và với tham số true để xác định primary key thì tương đương với việc bạn đặt DataTable.PrimaryKey như trong phần trên.

Để xem DataTable có các constraint nào, bạn chỉ cần lặp qua các phần tử trong collection DataTable.Constraint.

ForeignKeyConstraint

Constraint này được dùng để tạo relation giữa hai cột thuộc hai table (tạo foreign key cho bảng).  ForeignKeyConstraint phải được thêm vào table con vì đây là table chứa foreign key

. Ví dụ ta tạo constraint này cho cột GroupID của hai table Group và User:

DataColumn parent = dataSet.Tables["Group"].Columns["GroupID"];
DataColumn child = dataSet.Tables["User"].Columns["GroupID"];

ForeignKeyConstraint constraint = new ForeignKeyConstraint("FK_Group_User", parent, child);

constraint.UpdateRule = Rule.Cascade;
constraint.DeleteRule = Rule.SetNull;

dataSet.Tables["User"].Constraints.Add(constraint);

Sau khi đặt constraint này, nếu thử thêm một user có GroupID không nằm trong table Group, bạn sẽ nhận được một exception “InvalidConstraintException”

dataSet.Tables[“User”].Rows.Add(13, “Test”, 999);

InvalidConstraintException: ForeignKeyConstraint FK_Group_User requires the child key values (99) to exist in the parent table.

Một điểm chú ý là constraint này không tương đương với việc bạn đặt relation trong DataSet. Vì vậy bạn không thể dùng các phương thức GetChildRows(), GetParentRow().

Enum Rule

Enum này có bốn giá trị mà bạn có thể sử dụng, theo mô tả dưới đây.

Rule setting Description
Cascade Delete or update related rows.
SetNull Set values in related rows to DBNull.
SetDefault Set values in related rows to the default value.
None Take no action on related rows. This is the default.

Như ví dụ trên, thuộc tính UpdateRule của constraint được đặt mặc định là Rule.Cascade để nếu có thay đổi từ table cha, các dòng tương ứng trong table con sẽ tự động cập nhật lại. Hoặc các dòng dữ liệu tương ứng trong table con sẽ bị xóa nếu như table cha xóa một dòng dữ liệu.

Bạn thử sửa GroupID đầu tiên của table Group từ 1 thành 9. Sau đó kiểm tra lại table User xem các dòng có GroupID ban đầu là 1 có chuyển thành 9 không:

dataSet.Tables["Group"].Rows[0]["GroupID"] = 9;

foreach(DataRow row in dataSet.Tables["User"].Select("GroupID='9'"))
Console.WriteLine(row["UserName"]);

Output:

Adon
Balrog
Bison
Cammy
ChunLi
Dan
DeeJay

Luật thứ hai DeleteRule = Rule.SetNull để quy định rằng nếu dữ liệu bên table cha bị xóa, các dòng tương ứng trong table con sẽ được gán bằng DBNull.

7 thoughts on “ADO.NET – Cơ bản về DataSet (Part 2/2): DataRelation và Constraint

  1. Pingback: ADO.NET – Làm việc với Strongly Typed DataSet « YinYang's Programming Blog

  2. Hi Yin Yang

    Tôi có code theo cách bạn nói mà ko được nè

    DataSet ds = LoadData(); // method LoadData return a DataSet tương tự như cách bạn code ở part 1

    combobox.DataSource = ds.Tables[“Users”].Select(“UserID = 1”);
    combobox.DisplayMember = “UserName”;
    combobox.ValueMember = “UserID”;

    Trả lời
  3. Xin lỗi vì chưa kiểm tra trước khi giải đáp cho bạn. Nguyên nhân là do Combobox ko tìm được các thông tin tên cột (hay property của đối tượng được binding). Điều này có vẻ hơi ngớ ngẩn nhưng cách giải quyết là bạn cần phải add các row này vào trong một DataTable rồi mới binding được. Hoặc cách tốt hơn là bạn ko nên dùng Select(). Bạn nên sử dụng RowFilter của DataView để lọc dữ liệu.

    Trả lời
  4. Hi Yin Yang

    Bạn có thể chỉ tui cách tạo relation giữa 01 DataTable có 01 column là Primary Key & 01 DataTable có 2 columns là Primary Key được ko? Tui có ví dụ như sau:
    _ds.Tables[“A”].PrimaryKey = new DataColumn[] { _ds.Tables[“A”].Columns[“IdA”] };
    _ds.Tables[“B”].PrimaryKey = new DataColumn[] { _ds.Tables[“B”].Columns[“IdB”],_ds.Tables[“B”].Columns[“IdC”] };
    // How to Set relations here?
    _ds.Relations.Add(“M_D”, ?,?);

    Trả lời

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s