Ở bài trước mình đã giới thiệu về cách viết SQL statement và thực thi (execute) câu lệnh. Ở bài này mình sẽ tóm tắt về các sử dụng Data Readers.
Data Readers được dùng để :
· Thu nhận kết quả từ các query
· Lấy thông tin về các cột các hàng trong bảng dữ liệu
· Lấy thông tin result set
· Lấy thông tin về schema
· Xử lý các result sets
Tổng quát về Data Readers (Data Readers in General)
Thành phần thứ ba của nhà cung cấp dữ liệu là ‘data reader’, 2 thành phần trước là ‘connection’ và ‘command’. Một khi đã tạo được kết nối tới cơ sở dữ liệu và thi hành các lệnh query thì chúng ta cần một phương thức nào đó để hỗ trợ cách xử lý dữ liệu thu nhận được. Nếu bạn đã biết về ADO thì một ADO.NET data reader giống như là ADO recordset một chiều phía client, chứ không phải là một đối tượng COM.
Data readers là các đối tượng được cung cấp trong lớp interface ‘System.Data.IdataReader’. Một ‘data reader’ có thể gọi là một stream đã kết nối tới cơ sở dữ liệu đọc dữ liệu hiệu quả, theo một chiều và thu nhận dữ liệu theo từng dòng (row).Vì vậy không thể trực tiếp xử lý data reader mà phải xử lý thông qua phương thức ‘ExecuteReader’ của một đối tượng command. Ví dụ
Visual C# Code:
  1. SqlConnection conn = new SqlConnection(connectionString);
  2. SqlCommand cmd = new SqlCommand(new string(“query command”), conn);
  3. SqlDataReader reader = cmd.ExecuteReader();
Đoạn code ở trên là minh họa cách tạo một đối tượng trong lớp SqlDataReader.
Chú ý: Quy tắc chung khi sử dụng data reader dơn giản là chỉ thu nhận và trình bày kết quả thu được.Phân biệt data reader với dataset, cả 2 đều được tạo ra với mục đích khác nhau mặc dù cách nhìn nhận chung thì đều thu nhận kết quả.
Thử một vài ví dụ làm việc với Data Reader
Visual C# Code:
  1. using System;
  2. using System.Data;
  3. using System.Data.SqlClient;
  4.  
  5. public class ThiHanhMenhLenh
  6. {
  7.     public static void Main()
  8.     {
  9.         // Tạo connection
  10.         SqlConnection conn = new SqlConnection(@"Server = .\SQLEXPRESS;
  11.                                                 Integrated Security = True;
  12.                                                 Database = Northwind");
  13.         // Tạo query
  14.         string sql = @"SELECT contactname FROM customers";
  15.         try
  16.         {
  17.             // Mở kết nối
  18.             conn.Open();
  19.             // Tạo command
  20.             SqlCommand cmd = new SqlCommand(sql, conn);
  21.             // Tạo Data Reader
  22.             SqlDataReader reader = cmd.ExecuteReader();
  23.             while (reader.Read())
  24.             {
  25.                 Console.WriteLine(" {0} ", reader[0]);
  26.             }
  27.         reader.Close();
  28.         }
  29.         catch (SqlException sqle)
  30.         {
  31.             // Thông báo lỗi
  32.             Console.WriteLine(sqle.ToString());
  33.         }
  34.         finally
  35.         {
  36.             // Đóng kết nối
  37.             conn.Close();
  38.             Console.WriteLine("Close connection !");
  39.         }
  40.     }
  41. }
Trong vòng lặp thu kết quả của ‘data reader’ (reader) phương thức ‘Read()’ trỏ đến giá trị hàng tiếp theo (nếu có) . Bản chất khi reader đã có kết quả sau khi thực thi query thì reader nắm giữ toàn bộ record thu được. vì vậy có thể dùng index để gọi đến một giá trị bất kì trong kết quả thu được nằm trong giới hạn của bound.
Cuối cùng thì phải đóng lại reader. Tại sao đóng ? Vì khi đã kết nối và reader được gắn vào kết nối thì reader sẽ nằm ở đó để lấy dữ liệu khi xử lý. Cứ tưởng tượng một ngôi nhà mà chỉ có người vào không có người ra thì đến một lúc nào đó sẽ không vào được nữa mà muốn ra cũng không được. Tương tự như vậy, phải đóng lại reader sau mỗi lần đọc.
Ví dụ dưới đây minh họa cách sử dụng index gọi giá trị column khi Read()
Visual C# Code:
  1. using System;
  2. using System.Data;
  3. using System.Data.SqlClient;
  4.  
  5. public class ThiHanhMenhLenh
  6. {
  7.     public static void Main()
  8.     {
  9.         // Tạo connection
  10.         SqlConnection conn = new SqlConnection(@"Server = .\SQLEXPRESS;
  11.                                                 Integrated Security = True;
  12.                                                 Database = Northwind");
  13.         // Tạo query
  14.         string sql = @"SELECT companyname,contactname FROM customers WHERE contactname LIKE 'M%'";
  15.         try
  16.         {
  17.             // Mở kết nối
  18.             conn.Open();
  19.             // Tạo command
  20.             SqlCommand cmd = new SqlCommand(sql, conn);
  21.             // In headings
  22.             Console.WriteLine("\t{0} {1}", "Company Name".PadRight(25), "Contact Name".PadRight(20));
  23.             Console.WriteLine("\t{0} {1}", "============".PadRight(25), "============".PadRight(20));
  24.  
  25.             // Tạo Data Reader
  26.             SqlDataReader reader = cmd.ExecuteReader();
  27.             while (reader.Read())
  28.             {
  29.                 Console.WriteLine("{0} | {1}", reader[0].ToString().PadLeft(25),reader[1].ToString().PadLeft(20));
  30.             }
  31.             reader.Close();
  32.         }
  33.         catch (SqlException sqle)
  34.         {
  35.             // Thông báo lỗi
  36.             Console.WriteLine(sqle.ToString());
  37.         }
  38.         finally
  39.         {
  40.             // Đóng kết nối
  41.             conn.Close();
  42.             Console.WriteLine("Close connection !");
  43.         }
  44.     }
  45. }
Kết quả thu được trong reader thu về là kiểu object . Vì vậy ở trên mình convert các object sang kiểu string (ToString()) sau đó căn lề. Cuối cùng đóng kết nối để giải phóng khỏi kết nối.
Nhiều lúc cũng chẳng biết là cột số mấy vị trí nào hơi phức tạp. Lớp SqlDataReader cung cấp cho đối tượng cách chỉ định index bằng tên cột.
Visual C# Code:
  1. reader[“companyname”].ToString().PadLeft(25);
  2. reader[“contactname”].ToString().PadLeft(20);
Tuy nhiên 2 cách trên đều không tối ưu. Vì khi truy cập vào bảng dữ liệu kết quả thu được giữ tạm thời theo kiểu của .NET chứ không phải kiểu ban đầu trong tài nguyên. Hai cách ở trên mỗi lần lấy một kết quả đều kiểm tra xem dữ liệu kiểu gì và convert kiểu nên không tối ưu.
Do đó phương thức lấy dữ liệu theo kiểu được cung cấp , tất cả bắt đầu với ‘Get’
Dưới đây là 2 bảng dữ liệu tương ứng các kiểu dữ liệu trong SQLServer và OLE DB với .NET
Bảng 1 : Kiểu dữ liệu trong SQL Server và .NET
Click vào hình ảnh để lấy hình ảnh lớn

Tên:		photo1.jpg
Lần xem:	234
Size:		80.0 KB
ID:		5072

Bảng 2 : Kiểu dữ liệu trong OLE DB và .NET
Click vào hình ảnh để lấy hình ảnh lớn

Tên:		photo2.jpg
Lần xem:	115
Size:		99.0 KB
ID:		5073

Ví dụ bảng Products trong Northwind
Click vào hình ảnh để lấy hình ảnh lớn

Tên:		photo3.jpg
Lần xem:	122
Size:		33.3 KB
ID:		5074

Dưới đây là đoạn code minh họa cách sử dụng phương thức truy cập theo kiểu dữ liệu :
Visual C# Code:
  1. using System;
  2. using System.Data;
  3. using System.Data.SqlClient;
  4.  
  5. public class ThiHanhMenhLenh
  6. {
  7.     public static void Main()
  8.     {
  9.         // Tạo connection
  10.         SqlConnection conn = new SqlConnection(@"Server = .\SQLEXPRESS;
  11.                                                 Integrated Security = True;
  12.                                                 Database = Northwind");
  13.         // Tạo query
  14.         string sql = @"SELECT productname, unitprice, unitsinstock, discontinued FROM products";
  15.         try
  16.         {
  17.             // Mở kết nối
  18.             conn.Open();
  19.             // Tạo command
  20.             SqlCommand cmd = new SqlCommand(sql, conn);            
  21.  
  22.             // Tạo Data Reader
  23.             SqlDataReader reader = cmd.ExecuteReader();
  24.             while (reader.Read())
  25.             {
  26.                 Console.WriteLine("{0}\t{1}\t\t{2}\t{3}",
  27.                                     reader.GetString(0).PadRight(30),
  28.                                     reader.GetDecimal(1).ToString().PadLeft(8),
  29.                                     reader.GetInt16(2),
  30.                                     reader.GetBoolean(3));
  31.             }
  32.             reader.Close();
  33.         }
  34.         catch (SqlException sqle)
  35.         {
  36.             // Thông báo lỗi
  37.             Console.WriteLine(sqle.ToString());
  38.         }
  39.         finally
  40.         {
  41.             // Đóng kết nối
  42.             conn.Close();
  43.             Console.WriteLine("Close connection !");
  44.         }
  45.     }
  46. }
Lấy thông tin về Data
Ví dụ dưới đây lấy thông tin về schema của bảng :
Visual C# Code:
  1. using System;
  2. using System.Data;
  3. using System.Data.SqlClient;
  4. using System.Xml;
  5. public class DataReader
  6. {
  7.     public static void Main()
  8.     {
  9.         // Tạo connection
  10.         SqlConnection conn = new SqlConnection(@"Server = .\SQLEXPRESS;
  11.                                                 Integrated Security = True;
  12.                                                 Database = Northwind");
  13.         // Tạo query
  14.         string sql = @"SELECT productname, unitprice, unitsinstock, discontinued FROM products";
  15.         try
  16.         {
  17.             // Mở kết nối
  18.             conn.Open();
  19.             // Tạo command
  20.             SqlCommand cmd = new SqlCommand(sql, conn);            
  21.  
  22.             // Tạo Data Reader
  23.             SqlDataReader reader = cmd.ExecuteReader();
  24.             DataTable table = reader.GetSchemaTable();
  25.  
  26.             foreach (DataRow row in table.Rows)
  27.             {
  28.                 foreach (DataColumn col in table.Columns)
  29.                 {
  30.                     Console.WriteLine("{0} = {1}", col.ColumnName, row[col]);
  31.                 }
  32.                 Console.WriteLine("===========================");
  33.             }
  34.            
  35.             reader.Close();
  36.         }
  37.         catch (SqlException sqle)
  38.         {
  39.             // Thông báo lỗi
  40.             Console.WriteLine(sqle.ToString());
  41.         }
  42.         finally
  43.         {
  44.             // Đóng kết nối
  45.             conn.Close();
  46.             Console.WriteLine("Close connection !");
  47.         }
  48.     }
  49. }
Ở đây dùng ‘GetSchemaTable’ để lấy về thông tin Schema, như tên gọi thì kết quả trả về kiểu DataTable. Vì vậy ta phải xử lý DataTable bằng DataRow và DataColumn.
Bảng dưới đây là các method được cung cấp để lấy thông tin về dữ liệu
Click vào hình ảnh để lấy hình ảnh lớn

Tên:		photo4.jpg
Lần xem:	150
Size:		41.9 KB
ID:		5075

Xử lý nhiều result sets với một data reader
Ví dụ gọi một lúc nhiều query và một data reader thì việc xử lý dữ liệu thu được dường như phức tạp nhưng .NET có cung cấp một phương thức để làm việc với thao tác này ‘NextResult()’
Ví dụ dưới đây minh họa thao tác xử lý nhiều result sets với một reader
Visual C# Code:
  1. using System;
  2. using System.Data;
  3. using System.Data.SqlClient;
  4. using System.Xml;
  5. public class DataReader
  6. {
  7.     public static void Main()
  8.     {
  9.         // Tạo connection
  10.         SqlConnection conn = new SqlConnection(@"Server = .\SQLEXPRESS;
  11.                                                 Integrated Security = True;
  12.                                                 Database = Northwind");
  13.         // Tạo query
  14.         string sql1 = @"SELECT productname, unitprice FROM products ";
  15.         string sql2 = @"SELECT firstname, lastname FROm employees ";
  16.         string sql = sql1 + sql2;
  17.         try
  18.         {
  19.             // Mở kết nối
  20.             conn.Open();
  21.             // Tạo command
  22.             SqlCommand cmd = new SqlCommand(sql, conn);            
  23.  
  24.             // Tạo Data Reader
  25.             SqlDataReader reader = cmd.ExecuteReader();
  26.             do
  27.             {
  28.                 while (reader.Read())
  29.                 {
  30.                     Console.WriteLine("\t{0} - {1}", reader[0], reader[1]);
  31.                 }
  32.                 Console.WriteLine("".PadLeft(60,'='));
  33.             } while (reader.NextResult());            
  34.             reader.Close();
  35.         }
  36.         catch (SqlException sqle)
  37.         {
  38.             // Thông báo lỗi
  39.             Console.WriteLine(sqle.ToString());
  40.         }
  41.         finally
  42.         {
  43.             // Đóng kết nối
  44.             conn.Close();
  45.             Console.WriteLine("Close connection !");
  46.         }
  47.     }
  48. }
Ở đây có 2 query và từng query được xử lý lần lượt. Chú ý các query phải có một kí tự ngăn cách để kiểm tra hợp lệ, trong SQL Server thì đơn giản chỉ cần một dấu cách (space) là được.
Kết thúc về sử dụng Data Readers.

Mục lục:
1. Giới thiệu cơ bản ngôn ngữ SQL
2. Giới thiệu cơ bản về ADO.NET
3. Tạo kết nối tới database
4. Thực thi câu lệnh SQL
5. Xử lý kết quả với Data Reader
6. Cách xử lý dữ liệu với Data Adapter và DataSet
7. Giới thiệu về DataBinding