Sei sulla pagina 1di 22

ADO.NET 2.

0 (phҫn 1)
Cұp nhұt: 6/7/2008 08:32 AM vӟi no comments
c  

      
     !"#   $ % &
' ( c   )* + 
 , " -./0 1 /  23 # /  /4 5 / % /" *  
6" 7     *   c  8"  9""  )"  
  :  2  /4 / ;
3 / < 2 *=  / 7     *   c  8"  9"" += /   % > 
/ #/2"?  /@ c
 "c /   A".

BBc )/5.

ĐiӅu quan trӑng khi tҥo Business Entity là sӱ dөng Visual Studio 2005 đӇ tҥo Typed-DataSet, tҥo cҩu
trúc Class giӕng vӟi cҩu trúc Table cӫa RDBMS (Relational Database Management System). NӃu sӱ
dөng nguyên DataSet class cӫa System Data Namespace thҩy trong sách vӣ, thì không thӇ thӓa mãn
đưӧc yêu cҫu vӅ business application.

ĐiӅu quan trӑng khi tҥo Data Access Logic Component là sӱ dөng Visual Studio 2005, đӇ tҥo tӵ đӝng
TableAdapter. NӃu TableAdapter đưӧc sinh tӵ đӝng bҵng Visual Studio 2005 thì source code mӣ kӃt nӕi
dӳ liӋu, tҥo câu lӋnh SQL sӁ tӵ đӝng đưӧc sinh ra cho nên sӁ giҧm đưӧc công sӭc. Hơn hӃt, có thӇ
tránh đưӧc viӋc Logic đӇ truy cұp data đưӧc viӃt trong presentation như Windows Forms và ASP.NET,
và khi phát sinh trùng sӁ không thӇ bҧo trì.

Sau đây chúng tôi xin mô tҧ chi tiӃt hơn vӅ nhӳng vҩn đӅ này.

93 /6"7   


Business Entity là class hiӇn thӏ Data đưӧc xӱ lý trong business application. Tҩt cҧ business application,
không có ngoҥi lӋ, sӁ xӱ lí data. Ví dө như trong phân phӕi sҧn phҭm thì nó là thông tin sҧn phҭm, thông
tin khách hàng, thông tin lưu kho... Microsoft gӑi class group đӇ xӱ lí các data mӝt cách hiӋu quҧ và
thӕng nhҩt là Business Entity. (Mһt khác, class group có vai trò tương tӵ trong Community cӫa phân
tích/thiӃt kӃ hưӟng đӕi tưӧng cũng đưӧc gӑi là Domain Object).

Có 2 phương pháp tҥo Business Entity trong .NET Framework 2.0. Đó là phương pháp sӱ dөng nguyên
DataSet class, và phương pháp sӱ dөng Visual Studio 2005 đӇ cho sinh tӵ đӝng Typed-DataSet.
(Phương pháp tҥo class đӝc lұp trong Java...cũng đưӧc xem xét, tuy nhiên nӃu làm như vұy thì sӁ mҩt đi
ý nghĩa cӫa viӋc sӱ dөng .NET Framework 2.0. Vì thӃ trong tài liӋu này sӁ bӓ qua phương pháp đó.)

Sau đây, chúng tôi xin trình bày các vҩn đӅ cӫa phương pháp sӱ dөng nguyên DataSet class, và cách
Typed-DataSet giҧi quyӃt nhӳng vҩn đӅ đó.

Trong tài liӋu này sӁ sӱ dөng ER Diagram như dưӟi đӇ làm rõ vҩn đӅ này.
93 *$= C /D</3 &'E  , 

Dưӟi đây là source code cө thӇ cho phương pháp sӱ dөng nguyên DataSet class. NӃu compile rӗi thӵc
hiӋn source code dưӟi, thì sӁ output ra màn hình console nhӳng sҧn phҭm có giá trӏ dưӟi $2000.00.

// Tңo DataSet
using (DataSet ds = new DataSet())
{
// Tңo connection.
using (SqlConnection sc = new SqlConnection(
"Data Source=localhost\\SQLExpress; Initial Catalog=UsolV; Integrated
Security=true;"))
{
// Tңo DataAdapter.
using (SqlDataAdapter sda = new SqlDataAdapter("select * from
Product where price <= 2000.00", sc))
{
// Sӯ dӧng DataAdapter, đӅ lҧy data cөa Product Table.
sda.Fill(ds, "Product");
}
}

// Xác nhүn viӉc lҧy dӱ liӉu đúng.

// Tҧt cҥ DataRow cөa Product Table đã lҧy.


foreach (DataRow dr in ds.Tables["Product"].Rows)
{
// Output ra màn hình Console
Console.WriteLine("{0}\r\n{1}\r\n{2:c}\r\n", dr["Name"],
dr["Description"], dr["Price"]);
}
}
(ViӃt ra chӍ nhҵm mөc đích tham khҧo) using là tӯ dành riêng đӇ gӑi tӵ đӝng Dispose() method. ViӋc giҧi
phóng memory trong .NET Framework 2.0 đưӧc garbage collection làm tӵ đӝng, tuy nhiên không tӵ đӝng
giҧi phóng trong trưӡng hӧp đã sӱ dөng resource như kӃt nӕi thông tin. Đӕi vӟi business application có
yêu cҫu đӝ tin cұy, trong trưӡng hӧp sӱ dөng resource ngoài bӝ nhӟ thì F ; phҧi gӑi
Dispose()method. Đây là viӋc rҩt phӭc tҥp (đӇ có thӇ gӑi đưӧc Dispose()method ngay cҧ khi phát sinh
ngoҥi lӋ thì phҧi viӃt try/finally), nên tӯ khóa using đưӧc sӱ dөng.

NӃu chӍ nhìn qua thì sӁ thҩy source code trên không có vҩn đӅ gì. NӃu Data Binding trên GridView cӫa
Windows Forms thì vүn có thӇ xӱ lí data. % /@ 1G 
, thì cũng không có vҩn đӅ lӟn gì xҧy ra cho
dù áp dөng phương pháp sӱ dөng nguyên DataSet.

,H/& / // 
/ I*$=E

Phương pháp đưӧc nghĩ tӟi đҫu tiên trong trưӡng hӧp 1 table bӏ chia thành 2 table là phương pháp
JOIN. Câu lӋnh SELECT trong phҫn source code trên đã thay đәi như dưӟi đây.

select
Product.Name, Product.Description, Product.Price, Category.Name
from
Product
inner join Category ON Product.CategoryIdentity = Category.[Identity]
where
Price <= 2000.00

Vӟi cách làm này, cho dù chia thành nhiӅu Table cũng không có vҩn đӅ gì. Mһc dù gҳn điӅu kiӋn nӃu chӍ
hiӋn thӏ data lên màn hình.Tuy nhiên vӟi phương pháp này sӁ rҩt khó khăn trong viӋc update data.

7J/D</3KL H$#/1#/M"*      

Lҩy kӃt quҧ đã JOIN và hiӇn thӏ ra bҧng. NӃu trong trưӡng hӧp câu lӋnh SELECT như trên thì sӁ hiӇn thӏ
ra bҧng như dưӟi đây. (ĐӇ thu gӑn màn hình sӁ lưӧc bӓ Product.Description.)

Product.Name Product.Price Category.Name


Y 
Y Y 


Y  Y 


  
Y
  

Chúng ta sӁ thӱ cùng suy nghĩ. NӃu thay Category.Name cӫa dòng đҫu tiên thành "IBM ThinkPad
Series" thì sӁ như thӃ nào? Có update Name cӫa Category Table không? NӃu đӇ nguyên là "Lenovo
ThinkPad Series" thì dòng thӭ 2 sӁ không bӏ chӍnh sӱa? NӃu xóa đi dòng thӭ 3 thì category Sony VAIO
Series sӁ như thӃ nào?có bӏ xóa đi không? Thì có lӁ chӍ thình thoҧng mӟi thҩy trên màn hình xuҩt hiӋn
sҧn phҭm Sony VAIO Series vӟi giá >=2000$.

Vӟi lý do trên, sӁ không thӇ sӱ dөng JOIN trong trưӡng hӧp update. Hҫu hӃt trong các business
application đӅu có Update Data. Vì thӃ, trong business application mà chӍ dӵa vào JOIN thì rҩt nguy
hiӇm.

/N %/0 1/D / =   


*"  , 
wĩ thuұt viên Microsoft nhӳng ngưӡi đã tҥo .NET Framework 2.0 tҩt nhiên nҳm đưӧc nhӳng điӅu đã trình
bày đӃn đây. Vì vұy trên thӵc tӃ, trong DataSet đã chuҭn bӏ sҹn cҩu trúc đӇ có thӇ xӱ lí nhiӅu Table mӝt
cách tӵ nhiên. Dưӟi đây là source code cө thӇ đã sӱ dөng function đó.

// Tңo DataSet.
using (DataSet ds = new DataSet())
{
// Tңo Connection.
using (SqlConnection sc = new SqlConnection(
"Data Source=localhost\\SQLExpress; Initial Catalog=UsolV; Integrated
Security=true;"))
{
// Trưӝc tiên, lҧy tҧt cҥ các Category.
using (SqlDataAdapter sda = new SqlDataAdapter("select * from
Category", sc))
{
sda.Fill(ds, "Category");
}

// Lҧy tҧt cҥ các sҥn phҫm có giá trӍ <= $2000.


using (SqlDataAdapter sda = new SqlDataAdapter("select * from
Product where Price <= 2000.00", sc))
{
sda.Fill(ds, "Product");
}
}

// Add thêm DataRelation liên kӁt category vӝi product.


ds.Relations.Add(new DataRelation("Category_Product",
ds.Tables["Category"].Columns["Identity"],
ds.Tables["Product"].Columns["CategoryIdentity"]));

// ĐӁn đây, có thӅ lҧy đưӥc Product Group thuӛc vào Category bҳng
DataRow GetChildRows("Category_Product") cөa DataRow cөa Category,
// và có thӅ lҧy đưӥc category có chӫa product bҳng
GetParentRow("Category_Product") cөa DataRow cөa product.

// Xác nhүn xem lҧy dӱ liӉu có đúng không.

// Tҧt cҥ DataRow cөa product table đã lҧy.


foreach (DataRow dr in ds.Tables["Product"].Rows)
{
// Output ra màn hình Console.
Console.WriteLine("{0}\r\n{1}\r\n{2:c}\r\n{3}\r\n",
dr["Name"], dr["Description"], dr["Price"],
dr.GetParentRow("Category_Product")["Name"]);

// Vì có thӅ lҧy đưӥc DataRow cөa category bҳng


GetParentRow("Category_Product")
// cho nên có thӅ hiӅn thӍ category name nӁu là
dr.GetParentRow("Category_Product")["Name"].
}
}

Point chính là viӋc gӑi ra Add()method đӕi vӟi Relations Property cӫa DataSet. NӃu vӟi cách viӃt source
code như trên thì sӁ không phát sinh các vҩn đӅ giӕng như trong trưӡng hӧp JOIN. Tuy nhiên là do chӍ
có 1 dòng Category giӕng như trên RDBMS. (Trong source code trên có vҩn đӅ là sӁ lҩy tҩt cҧ, kӇ cҧ
nhӳng Category không cҫn thiӃt. VӅ vҩn đӅ này sӁ giҧi quyӃt bҵng "Cách tҥo Data Access Logic
Component" sӁ mô tҧ ӣ phҫn sau.)

Vӟi lí do trên, nӃu làm DatSet mӝt cách cҭn thұn và sӱ dөng thì chҳc là sӁ đưӧc. Chҳc chҳn sӁ đưӧc,
nӃu như chúng ta lұp trình #/O/2 
 O*   /@
 P/4 /.

Tuy nhiên thì phương pháp sӱ dөng DataSet và DataRelation là phương pháp rҩt phiӅn toái. Trưӟc hӃt,
mӛi lҫn lҩy data tӯ RDBMS thì viӋc add thêm DataRelation rҩt phiӅn toái. Hơn nӳa thì cho đӃn đây,
chúng tôi cũng đã bӓ qua vҩn đӅ này, tuy nhiên thì viӋc viӃt kiӇu như dataRow["Ô "] cũng rҩt
phiӅn. ViӋc không đáng kӇ gì như thӃ này cũng trӣ thành vҩn đӅ là bӣi vì business application rҩt phӭc
tҥp đӃn mӭc không thӇ sӱ dөng GridView control , hiӇn thӏ lên màn hình và đưӧc ngưӡi sӱ dөng input
vào. Ví dө như viӋc kiӇm tra giá trӏ input, tính toán chi phí gӱi, lӵa chӑn các sҧn phҭm đưӧc giӟi thiӋu.
NӃu muӕn tҥo mӝt site vӅ electric commerce giӕng như amazon.com thì buӝc chúng ta phҧi viӃt source
code đӇ thӵc hiӋn nhӳng business logic phӭc tҥp như thӃ này. Giҧ sӱ trong phҫn source code đó có viӃt
dataRow["Ô "], thì sӁ tӕn chi phí cho viӋc input do không thӇ sӱ dөng IntelliSense trong string,
và sӁ tӕn chi phí cho viӋc test do không biӃt đưӧc là column name đӃn khi thӵc hiӋn thӱ có đúng không?

Vұy thì nên làm thӃ nào? Vâng, hãy sӱ dөng Typed-DataSet mà USOL ViӋt Nam đӅ xuҩt.

%
  Q  ,  /0 1 /  2  R% ; 3 / /O  / 2
/*$=/D/ = 
/  2/*$=
ER %*  
  
ĐӇ hiӇu đưӧc Typed-DataSet thì điӅu quan trӑng sӕ 1 là dùng thӱ nó. Hãy khӣi đӝng Visual Studio 2005,
tҥo project thích hӧp, rightclick vào project mà đã tҥo bҵng [Solution Explorer], lӵa chӑn [Add] - [New
Item...] tӯ pop up menu, lӵa chӑn [DataSet] icon tҥi hӝp thoҥi [Add New Item] và click vào nút [Ow]. whi
đó thì Typed-DataSet đưӧc tҥo. Sau khi Typed-DataSet đưӧc tҥo, hãy draft and drop table thích hӧp tӯ
[Server Explorer] như sơ đӗ dưӟi đây.

ĐӃn đây, thì viӋc tҥo Typed-DataSet đã hoàn thành. Vӟi nhӳng thao tác cho đӃn đây thì chúng ta có thӇ
giҧi quyӃt kӇ cҧ vҩn đӅ add thêm DataRelation mà trưӟc đây cҧm thҩy rҩt phiӅn toái, và cҧ vҩn đӅ bҳt
buӝc phҧi viӃt là dataRow["Ô "].Vӟi nhӳng căn cӭ như vұy thì chúng ta hãy dùng Typed-
DataSet và thӱ viӃt lҥi source code trên. Dưӟi đây là source code đã viӃt lҥi.

// Tңo Typed-DataSet.
using (CatalogDataSet ds = new CatalogDataSet())
{
// VӃ phҩn lҧy data thì giӓng vӝi trưӟng hӥp sӯ dӧng nguyên DataSet.
using (SqlConnection sc = new SqlConnection(
"Data Source=localhost\\SQLExpress; Initial Catalog=UsolV; Integrated
Security=true;"))
{
using (SqlDataAdapter sda = new SqlDataAdapter("select * from
Category", sc))
{
sda.Fill(ds, "Category");
}

using (SqlDataAdapter sda = new SqlDataAdapter("select * from


Product where Price <= 2000.00", sc))
{
sda.Fill(ds, "Product");
}
}

// Không cҩn add thêm DataRelation.

// Đã hoàn thành đӍnh nghĩa kiӅu cho dòng cөa sҥn phҫm, hơn nӱa cũng có
thӅ lҧy đưӥc DataTable bҳng property cөa tên giӓng vӝi tên table.
foreach (CatalogDataSet.ProductRow dr in ds.Product)
{
// Có thӅ lҧy đưӥc Data bҳng property cөa tên giӓng vӝi tên colum.
// Ngoài ra cũng có thӅ lҧy đưӥc category trӳc thuӛc trong
CategoryRow.
Console.WriteLine("{0}\r\n{1}\r\n{2:c}\r\n{3}\r\n",
dr.Name, dr.Description, dr.Price, dr.CategoryRow.Name);

// Ӡ đây chúng tôi không trình bày,


// nhưng có thӅ lҧy đưӥc product group thuӛc category bҳng
GetProductRows() cөa CategoryDataRow.
}
}

NӃu nhìn vào source code trên thì tôi nghĩ là mӑi ngưӡi có thӇ hiӇu phҫn sau hӃt sӭc đơn giҧn. (còn
phҫn phía trưӟc cũng sӁ đơn giҧn nӃu có thӇ sӱ dөng TableAdapter trình bày bҵng Fphương pháp tҥo
Data Access Logic Component ). whi đó sӁ không cҫn add thêm DataRelation, và nên viӃt
dataRow.Name hơn là dataRow["Name"], và nên viӃt là dataRow.CategoryRow.Name hơn là viӃt
dataRow.GetParentRow("Category_Product")["Name"] thì sӁ đơn giҧn hơn rҩt nhiӅu phҧi không? Vì có
thӇ sӱ dөng đưӧc IntelliSense, hơn nӳa dù tên cӝt bӏ sai đi nӳa chӍ cҫn compile là có thӇ hiӇu đưӧc.

Cơ chӃ (mechanism) cӫa Typed-DataSet có trong viӋc Visual Studio 2005 tӵ sinh source code . Bҥn hãy
thӱ click vào [+] ӣ bên trái cӫa Typed-DataSet trong [Solution Explorer] cӫa Visual Studio 2005. whi đó,
chҳc chҳn sӁ hiӋn ra file "Y 
   .Designer.cs" như hình dưӟi đây.
Chính "Y 
   .Designer.cs" nnày là phҫn source code mà Visual Studio 2005 tӵ sinh. NӃu
thӱ loҥi đi phҫn bên trong thì source code có add thêm DataRelation và source code access vào
DataRow["Name"] trong property name sӁ đưӧc mô tҧ. Vì Visual Studio 2005 làm cho chúng ta tҩt cҧ
nhӳng phҫn có thӇ làm mӝt cách máy móc, vì vұy chúng ta chӍ tұp trung vào nhӳng phҫn có tính chҩt
sáng tҥo, nhӳng phҫn thӵc hiӋn business logic trên source code.

1F
Business application rҩt phӭc tҥp. Phӭc tҥp ӣ ngay cҧ viӋc phҧi sӱ dөng nhiӅu table. Vì thӃ nên sӁ
biding data các DataTable có DataSet trong GridView control, hiӇn thӏ lên màn hình dưӟi dҥng bҧng,
không thӇ thӵc hiӋn đưӧc nӃu chӍ bҵng phương pháp đơn giҧn như cho input/output. (NӃu như chӍ
maintain 1 table thì làm bҵng Microsoft Access sӁ nhanh và rҿ hơn nhiӅu so vӟi làm chương trình bҵng
các Visual Studio 2005).

Bҵng viӋc sӱ dөng JOIN trong câu lӋnh SELECT, đӇ làm thành 1 bҧng, có thӇ giҧ coi như là chӍ có 1
bҧng. Tuy nhiên trong business application thì update là chӭc năng đi kèm, nӃu thӱ JOIN mӝt lҫn thì sӁ
không thӇ update đưӧc, vì thӃ không thӇ sӱ dөng đưӧc phương pháp này cho business application.

Cũng có thӇ phòng tránh bҵng viӋc làm cҭn thұn cách sӱ dөng Data Set. Vì có thӇ cho nhiӅu DataTable
vào trong DataSet, hơn nӳa còn có thӇ thiӃt lұp mӕi quan hӋ giӳa DataTable đó bҵng DataRelation. Vӟi
phương pháp này, thì data mà DataSet đang hiӇn thӏ sӁ có cҩu trúc giӕng vӟi data cӫa RDBMS, vì thӃ
đương nhiên có thӇ xӱ lí nhiӅu table, và update cũng đơn giҧn. ThӃ nhưng vì buӝc phҧi nhұp bҵng tay
table name, column name, relationship name cho nên vүn chưa thӓa mãn vӅ chi phí thӵc hiӋn và chi phí
test.

Tҩt cҧ nhӳng vҩn đӅ mà chúng tôi trình bày cho tӟi đây thì đӅu có thӇ giҧi quyӃt đưӧc bҵng viӋc sӱ dөng
Typed-DataSet. Typed-DataSet là phương thӭc mà Visual Studio 2005 tӵ sinh ra nhӳng property đӇ lҩy
table, colum, relationship bҵng nhӳng thao tác đơn giҧn như draft and drop table tӯ [Server Explorer].
NӃu như dùng phương pháp Typed-DataSet, thì vӟi chi phí thҩp nhҩt cũng có thӇ thӵc hiӋn phương
pháp sӱ dөng tӕi ưu nhӳng tính năng cӫa DataSet. Trong trưӡng hӧp muӕn tҥo business application
nhҩt đӏnh hãy thӱ sӱ dөng Typed-DataSet này.
ADO.NET 2.0 (phҫn 2)
Cұp nhұt: 6/7/2008 08:57 AM vӟi no comments
c  

      
     !"#   $ % &
' ( c   )* + 
 , " -./0 1 /  23 # /  /4 5 / % /" *  
6" 7     *   c  8"  9""  )"  
  :  2  /4 / ;
3 / < 2 *=  / 7     *   c  8"  9"" += /   % > 
/ #/2"?  /@ c
 "c /   A".

BBc )/5G.

93 /6"  c 8" 9"" 


Data Access Logic Component là class che dҩu thông tin vӟi RDBMS. Trên tҥp chí và Internet, cũng có
thӇ thҩy đưӧc source code mô tҧ trao đәi thông tin vӟi RDBMS trong event handler cӫa Windows Form
và Web Form, nhưng trong business application thì không chҩp nhұn cách làm như thӃ. Nói như vұy là
bӣi vì , nӃu mô tҧ trao đәi thông tin vӟi RDBMS trong event handler tӗn tҥi nhiӅu, thì sӁ phát sinh trùng
lһp mӝt lưӧng lӟn. NӃu trùng lһp, thì khi đã thay đәi cҩu trúc bҧng...phҧi thay đәi nhiӅu vӏ trí. Là con
ngưӡi nên chҳc chҳn phҧi mҳc lӛi, do đó sӁ trӣ thành hӋ thӕng rҩt khó maintenance. NӃu delivery hӋ
thӕng như thӃ thì sau đó chҳc chҳn sӁ không nhұn đưӧc order đӃn lҫn thӭ 2.

Vӟi lí do đó sӁ làm phҫn trao đәi thông tin vӟi RDBMS thành class đӝc lұp. Microsoft gӑi nhóm class đӝc
lұp đӇ trao đәi thông tin vӟi RDBMS là Data Access Logic Component. ( cũng có ngưӡi gӑi là Data
Access Object, nhưng nӃu gӑi như vұy thì sӁ trùng tên vӟi kӻ thuұt trao đәi thông tin vӟi RDBMS trong
thӃ hӋ Visual Basic cӫa Microsoft, do đó gҫn đây tên này không còn đưӧc sӱ dөng nӳa).

Có 2 phương pháp đӇ tҥo Data Access Logic Component trong .NET Framework 2.0 là:phương pháp sӱ
dөng y nguyên DataAdapter class và phương pháp sӱ dөng Visual Studio 2005 đӇ tҥo tӵ đӝng
TableAdapter. (cũng có phương thӭc sӱ dөng DataReader nhưng nó không gҫn gũi vӟi Typed-DataSet
đã ghi trong Fcách tҥo Business Entity nên trong này sӁ không đӅ cұp đӃn.) Trong viӋc lӵa chӑn 2 kӻ
thuұt trên , USOL-V nên chӑn TableAdapter. Dӭơi đây sӁ trình bày nhӳng vҩn đӅ cӫa phương pháp sӱ
dөng y nguyên DataAdapter Class, và TableAdapter sӁ giҧi quyӃt nhӳng vҩn đӅ đó như thӃ nào.

w/ODS T    c  9


J * / 

Nhӳng lұp trình viên, nhӳng ngưӡi kiӃm tiӅn bҵng viӋc phát triӇn các business application như chúng ta
không chӍ deliver binary sau khi compile, mà deliver cҧ source code trưӟc khi compile. Bӣi vì, sau khi
deliver, đӇ đӕi phó vӟi nhӳng thay đәi cӫa môi trưӡng business thì cҫn phҧi thay đәi source code, khi đó
ngưӡi order sӁ phҧi xem. Chính vì vұy nên tính maintenance cӫa source code rҩt quan trӑng. NӃu
delivery source code có tính maintenance thҩp thì chúng ta sӁ không nhұn đưӧc order lҫn thӭ 2. whi
tiӃng đӗn đó lan rӝng ra thì chúng ta chҳc chҳn cũng sӁ mҩt order tӯ công ty khác.

Vұy nên các lұp trình viên như chúng ta phҧi luôn suy nghĩ xem là làm thӃ nào đӇ nâng cao tính
maintenance. Đһc biӋt là cҫn phҧi loҥi bӓ triӋt đӇ trùng lһp có thӇ gây ra rҳc rӕi lӟn khi thay đәi. (Dù có
mӝt phҫn logic khó hiӇu nhưng nӃu phҫn đó không bӏ maintenance thì cũng không bӏ phát hiӋn. Nhưng
trưӡng hӧp có nhiӅu trùng lһp, sӁ bӏ phát hiӋn ngay bҵng regression test khi maintenance.) Ví dө. cҫn
phҧi tránh hoàn toàn tình trҥng câu SQL nҵm rҧi rác ӣ nhiӅu vӏ trí.

ĐӇ tránh sӵ trùng lһp này, hiӋu quҧ nhҩt là phҧi phân chia class theo vai trò. Business Entity đã mô tҧ ӣ
trên sӁ đҧm nhiӋm phҫn thӇ hiӋn data, còn Data Access Logic Component có trong chӫ đӅ hiӋn nay sӁ
đҧm nhiӋm phҫn trao đәi thông tin vӟi RDBMS. NӃu làm như vұy thì chӍ cҫn xem Data Access Logic
Component cũng có thӇ phán đoán có trùng lһp hay không trong trao đәi thông tin RDBMS. Chҳc chҳn
viӋc chӍ xem Data Access Logic Component sӁ dӉ dàng hơn so vӟi viӋc xem Windows Form và Web
Form cӫa source code lӟn tương ӭng vӟi nhiӅu chӭc năng. chҳc chҳn rҵng chӍ xem Business Entity và.
(Microsoft khuyӃn khích viӋc phân chia phҫn business logic thành Business Component, và phân chia
trao đәi thông tin giӳa client/ server thành Serivce Agent và Service Interface. Tương tӵ như vұy, Usol ±
V đang phân loҥi theo class như khuyӃn khích cӫa Microsoft và giҧm vùng thӯa có trùng lһp.)

,"  " ( #/ODS * %#/ /0UR      

ĐӇ sӱ dөng làm xuҩt phát điӇm cho buәi thҧo luұn này, trưӟc hӃt chúng tôi sӁ đưa ra nhӳng source code
chҩt lưӧng không tӕt, nhӳng source code mà nӃu deliver sӁ không nhұn đưӧc order nӳa. ĐӅ tài là Web
Form cӫa ASP.NET, hình ҧnh màn hình như sau.

*.aspx đӇ thӵc hiӋn màn hình này như sau.

<%@ Page Language="C#" AutoEventWireup="true"


Codebehind="UseDataAdapterWebForm.aspx.cs"
Inherits="DataAccessLogicComponent.UseDataAdapterWebForm" %>
<%@ Import Namespace="DataAccessLogicComponent" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>using the DataAdapter</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Repeater ID="catalogRepeater" DataSource='<%#
CatalogDataSet.Category.Rows %>' runat="server">
<HeaderTemplate>
<table border="1px">
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td colspan="2">
<%# HttpUtility.HtmlEncode(Eval("Name", "{0}")) %>
</td>
</tr>
<asp:Repeater ID="productRepeater" DataSource='<%#
((CatalogDataSet.CategoryRow)Container.DataItem).GetProductRows() %>'
runat="server">
<ItemTemplate>
<tr>
<td>
<%# HttpUtility.HtmlEncode(Eval("Name",
"{0}")) %>
</td>
<td>
<%# HttpUtility.HtmlEncode(Eval("Price",
"{0:c}")) %>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
<FooterTemplate>
</tbody>
</table>
</FooterTemplate>
</asp:Repeater>
</form>
</body>
</html>

Trong phҫn <%# ... %> cӫa source code trên có sӱ dөng chӭc năng data binding cӫa ASP.NET. Giҧi
thích chi tiӃt vӅ ASP.NET chúng tôi sӁ nói trong mӝt dӏp tӟi, còn ӣ đây, cho phép chúng tôi đưӧc giҧi
thích mӝt cách đơn giҧn. Trong phҫn ngӳ pháp data binding cӫa ASP.NET, ӣ giӳa "<%#" và "%>", có thӇ
viӃt bҩt cӭ công thӭc nào nӃu .NET Framework 2.0.có thӇ giҧi thích đưӧc. Ví dө như, 1 + 1, hay"Hello" +
"World", hay CatalogDataSet.Category.Rows. NӃu ghi như này và tiӃn hành DataBind() bҵng *.aspx.cs
thì công thӭc sӁ đưӧc đánh giá tҥi thӡi điӇm (timing) đó, giá trӏ sӁ đưӧc đưa vào HTML. Tuy nhiên,
Eval("Name", "{0}") sӁ đưӧc triӇn khai bҵng DataBinder.Eval(Container.DataItem, "Name", "{0}") , và sӁ
output ra name properties cӫa tӯng data mӛi khi repeater quay lҥi vòng lһp (trưӡng hӧp này là
CatalogDataSet.CategoryRow). VӅ "{0}" ӣ phía sau, hãy tham khҧo Format() method cӫa string class
(whi Name thì không chӍ đӏnh format đһc biӋt, nhưng khi là cách viӃt khác vӟi trưӡng hӧp Price thì tính
maintenance sӁ giҧm sút, do đó phҧi gҳn thêm format). ĐӇ phòng tránh viӋc tҩn công Cross Site
Scripting thì HttpUtility.HtmlEncode() method sӁ thay đәi "<" thành "&lt;". (Tҩn công Cross Site Scripting
là phương pháp cracking gӱi scipt đӇ tҩn công toàn bӝ site.) NӃu delivery source code không làm method
HttpUtility.HtmlEncode() thì sӁ phát sinh vҩn đӅ vӅ security , và các vҩn đӅ bӗi thưӡng do mҩt order nên
chҳc chҳn các bҥn không đưӧc quên.

Tӯ phҫn sau sӁ là source code cӫa *.aspx.cs thұt.

public partial class UseDataAdapterWebForm : Page


{
// Typed-DataSet.
private CatalogDataSet catalogDataSet;
// Properties đӅ access vào Typed-DataSet. ĐӅ có thӅ access tӭ *.aspx,
thì sҿ làm cách truy cүp control thành protected.
protected CatalogDataSet CatalogDataSet
{
get { return catalogDataSet; }
set { catalogDataSet = value; }
}

// Event handler khi page đã đưӥc load.


protected void Page_Load(object sender, EventArgs e)
{
// NӁu không post back...
if (!IsPostBack)
{
// Sҿ tңo ra instance cөa Typed-DataSet.
CatalogDataSet = new CatalogDataSet();

// Lҧy data tӭ RDBMS.


using (SqlConnection sc = new SqlConnection(
"Data Source=localhost\\SQLExpress; Initial Catalog=UsolV;
Integrated Security=true;"))
{
using (SqlDataAdapter sda = new SqlDataAdapter("select *
from Category", sc))
{
sda.Fill(CatalogDataSet, "Category");
}

using (SqlDataAdapter sda = new SqlDataAdapter("select *


from Product", sc))
{
sda.Fill(CatalogDataSet, "Product");
}
}

// Thӳc hiӉn data binding.


DataBind();
}
}
}

Hãy xem source code phía trên và tưӣng tưӧng. Có nhiӅu khҧ năng là ӣ chӛ khác cũng có Web Form xӱ
lý product và category, có thӇ ӣ đó cũng viӃt nhӳng câu lӋnh SQL tương tӵ. Giҧ sӱ nӃu bҧng Product
đưӧc thay đәi đӇ mӣ rӝng? SӁ phҧi update nhiӅu chӛ, do đó tính maintain sӁ bӏ giҧm đi. Cho dù có rҩt ít
vӏ trí sӱ dөng cùng mӝt câu lӋnh SQL và chӍ là Web Form này đi nӳa, nhưng vӟi cách tҥo source code
như trên, sӁ rҩt vҩt vҧ trong viӋc tìm xem cҫn phҧi thay đәi ӣ chӛ nào, vì vұy tҩt nhiên tính bҧo trì sӁ bӏ
giҧm đi. Có thӇ source code trên khó hiӇu nhưng bӣi vì chҳc chҳn rҵng xӱ lý Web Form sӁ còn phӭc tҥp
hơn và cҫn phҧi tìm kiӃm câu lӋnh SQL nҵm trong xӱ lý phӭc tҥp đó.

%;/ "  *V W 7X, ;


#/3 /04/2"0 H
DS M
E

ĐӇ nâng cao tính bҧo trì, sӁ tәng hӧp phҫn trao đәi thông tin vào mӝt class khác như Data Access Logic
Component. Cө thӇ sӁ thành source code như sau.
public static class CatalogDataAccessLogicCompoenent
{
public static int FillCategory(CatalogDataSet dataSet)
{
// Get category tӭ RDBMS.
using (SqlConnection sc = new SqlConnection("Data
Source=localhost\\SQLExpress; Initial Catalog=UsolV; Integrated
Security=true;"))
{
using (SqlDataAdapter sda = new SqlDataAdapter("select * from
Category", sc))
{
return sda.Fill(dataSet, "Category");
}
}
}

// Get product tӭ RDBMS.


public static int FillProduct(CatalogDataSet dataSet)
{
using (SqlConnection sc = new SqlConnection("Data
Source=localhost\\SQLExpress; Initial Catalog=UsolV; Integrated
Security=true;"))
{
using (SqlDataAdapter sda = new SqlDataAdapter("select * from
Product", sc))
{
return sda.Fill(dataSet, "Product");
}
}
}
}

Web Form sӱ dөng Data Access Logic Component này sӁ thành source code như dưӟi đây. Vì phҫn
*.aspx giӕng nhau nên chӍ trình bày *.aspx.cs.

public partial class UseDataAccessLogicComponentWebForm : Page


{
private CatalogDataSet catalogDataSet;

protected CatalogDataSet CatalogDataSet


{
get { return catalogDataSet; }
set { catalogDataSet = value; }
}

protected void Page_Load(object sender, EventArgs e)


{
if (!IsPostBack)
{
// Tңo trưӟng hӥp (instance) cөa Typed-DataSet.
CatalogDataSet = new CatalogDataSet();

// Gӏi ra Data Access Logic Component rӕi get data.


CatalogDataAccessLogicCompoenent.FillCategory(CatalogDataSet);
CatalogDataAccessLogicCompoenent.FillProduct(CatalogDataSet);
// Thӳc hiӉn data binding.
DataBind();
}
}
}

NӃu so sánh vӟi source code trưӟc khi làm Data Access Logic Component thành mӝt class riêng biӋt, thì
source code này khá đơn giҧn. Giӳa 2 source code , mӝt là có thӇ hiӇu đưӧc toàn bӝ nӃu như hiӇu đưӧc
mӝt cách tuҫn tӵ tӯng class đơn giҧn có cung cҩp các tính năng đơn giҧn, còn mӝt thì buӝc phҧi hiӇu
mӝt lҫn tҩt cҧ nhӳng đӕi tưӧng phӭc tҥp đó, thì source code đҫu tiên dӉ hiӇu hơn. Con ngưӡi có hҥn chӃ
vӅ năng lӵc, vì vұy đӇ có thӇ hiӇu đưӧc nhӳng thӭ phӭc tҥp như là hӋ thӕng máy vi tính thì viӋc phân
chia thành nhӳng phҫn đơn giҧn như vұy sӁ rҩt hiӋu quҧ.

%
 
c  /0 1//Y /   c 8" 9"" 
; 3 //S
Z*< 2
Nhӳng kӻ thuұt viên cӫa Microsoft không nhӳng cӵc kǤ xuҩt sҳc mà còn rҩt thân thiӋn. Vì vұy mà sau khi
xem xét tҩt cҧ nhӳng điӅu mà tôi đã viӃt ra đӃn đây, hӑ đã xây dӵng mӝt cơ cҩu hӛ trӧ viӋc thӵc hiӋn
theo như nhӳng nӝi dung đó trong Visual Studio 2005. (Vì là vҩn đӅ business nên viӋc phҧi hӑc và nâng
cao service level là đương nhiênZ. Chӭc năng đó chính là TableAdapter.

Dưӟi đây tôi xin chiӃu lҥi screen capture cӫa Typed-DataSet mà tôi đã cho các bҥn xem ӣ phҫn Business
Entity. NӃu chú ý và nhìn kӻ tӯng bҧng mӝt, các bҥn sӁ thҩy rҵng ӣ nӱa dưӟi cӫa bҧng có viӃt Y
TableAdapter. Ngoài ra, nhӳng nӝi dung đưӧc ghi trong bҧng dưӡng như là method tương ӭng vӟi
Data Access Logic Component như Fill hay GetData().

Nӱa dưӟi là TableAdapter. NӃu click vào bҧng, chӑn [Add] - [Query...]ӣ Pop-up menu thì có thӇ add thêm
method vào TableAdapter. ViӋc lұp trình trӣ nên dӉ dàng hơn bҵng thao tác đơn giҧn như thӃ này là vì
Visual Studio 2005 có thӇ tӵ đӝng tҥo source code giӕng như khi Typed-DataSet , và source code đã
đưӧc sinh tӵ đӝng lҥi tӵ đӝng tҥo source code trong Y 
   .Designer.cs giӕng như trưӡng
hӧp Typed-DataSet.

L&
Z /E /"*" 
c  $< 2

Mһc dù nói vұy, nhưng nӃu viӋc add thêm method vào TableAdapter rҳc rӕi hơn là viӃt source code thì
cũng không còn ý nghĩa gì nӳa. (tool không bình thưӡng như thӃ này đang tӗn tҥi rҩt nhiӅu. Ví dө
designer Web Form cӫa Visual Studio 2005 không phҧi kiӇu cӫa Microsoft). Sau đây tôi xin giӟi thiӋu cө
thӇ trình tӵ add method vào TableAdapter, và tôi sӁ cho các bҥn thҩy nó đơn giҧn hơn rҩt nhiӅu so vӟi
viӋc viӃt source code bҵng tay.
Trưӟc tiên, click phҧi chuӝt vào bҧng Typed-DataSet, rӗi chӑn [Add] - [Query...] ӣ Pop-up menu.

Vì sӁ bӏ hӓi vӅ phương thӭc get data nên tҥi đây, hãy chӑn [Use SQL Statement] nguyên như mһc đӏnh.
Vì sӁ bӏ hӓi là câu lӋnh SQL nào nên tҥi đây, hãy chӑn [SELECT which returns rows] nguyên như mһc
đӏnh.
TiӃp đó là nhұp câu lӋnh SQL. NӃu tӵ tin vӅ SQL, bҥn có thӇ nhұp trӵc tiӃp ӣ đây cũng đưӧc, nhưng bҥn
có thӇ tҥo đưӧc câu lӋnh SQL mӝt cách rҩt đơn giҧn bҵng cách click vào nút [Query Builder...]. Lҫn này
đӇ giӟi thiӋu vӟi các bҥn, tôi sӁ click thӱ vào nút [Query Builder...].

Tҥi QueryBuilder, bҥn có thӇ mô tҧ điӅu kiӋn vào Filter như ӣ sơ đӗ dưӟi đây, cho tҥo lӋnh WHERE,
hoһc cho tҥo lӋnh ORDER BY bҵng Sort Type và Sort Order, hoһc click phҧi chuӝt vào bҧng trên, add
thêm bҧng rӗi tҥo JOIN. Lҫn này tôi chӍ đӏnh trӵc tiӃp giá trӏ làF<= 2000 và nӃu đӇ chӛ này làF<=
@maxPrice thì có thӇ cho tìm kiӃm bҵng giá trӏ đã chӍ đӏnh tӯ chương trình.
ChӍ đӏnh tên và loҥi method sӁ sinh tӵ đӝng. Ӣ USOL-V có quy đӏnh là chӍ chӍ đӏnh check box [Fill a
DataTable] rӗi lҩy tên method làm FillByYÔ . (Tôi sӁ chӍ trình bày như vұy
thôi, trong tài liӋu này cho phép tôi lưӧc bӟt lý do. Tôi sӁ trình bày vӅ Software Architecture ӣ mӝt trang
Web mà tôi dӵ đӏnh sӁ public trong mӝt ngày gҫn đây nên các bҥn hãy chӡ đӃn lúc đó.)
ĐӃn đây là kӃt thúc xӱ lý add thêm method vào TableAdapter. Tôi nghĩ là các bҥn đã hiӇu rҵng viӋc này
còn đơn giҧn hơn cҧ viӋc viӃt source code.
Và tôi cũng xin đưa ra chӭng cӟ vӅ viӋc đã add thêm method. Đó là ӣ ProductTableAdapter có mӝt
method "FillByPriceBelow2000()" đã đưӧc add.

Mӝt bҵng chӭng nӳa là *.aspx.cs sӁ gӑi ra TableAdapter như dưӟi đây.

public partial class UseTableAdapterWebForm : Page


{
private CatalogDataSet catalogDataSet;

protected CatalogDataSet CatalogDataSet


{
get { return catalogDataSet; }
set { catalogDataSet = value; }
}

protected void Page_Load(object sender, EventArgs e)


{
if (!IsPostBack)
{
// Tңo trưӟng hӥp (instance) cөa Typed-DataSet.
CatalogDataSet = new CatalogDataSet();

// Gӏi ra TableAdapter rӕi get data.


using (CatalogDataSetTableAdapters.CategoryTableAdapter ta = new
CatalogDataSetTableAdapters.CategoryTableAdapter())
{
ta.Fill(CatalogDataSet.Category);
}
using (CatalogDataSetTableAdapters.ProductTableAdapter ta = new
CatalogDataSetTableAdapters.ProductTableAdapter())
{
ta.FillByProductPriceBelow2000(CatalogDataSet.Product);
}

// Thӳc hiӉn data binding.


DataBind();
}
}
}
Vì dòng cӫa phҫn using tăng lên nên chi phí cũng tăng. Nhưng nӃu xem xét tӟi sӵ chênh lӋch giӳa chi
phí tҥo Data Access Logic Component bҵng tay và chi phí tҥo TableAdapter tӵ đӝng trong Visual Studio
2005thì có thӇ phҧi chi trҧ toàn bӝ. Usol-V khuyӃn khích dùng TableAdapter.

95 /[Z"D\/S
$ 
 "
 =# 0# %

SӁ suy nghĩ vӅ các vҩn đӅ đã đưa ra trưӟc, vҩn đӅ sӁ get tҩt cҧ catagory.

Vӟi source code lúc nãy thì sӁ get tҩt cҧ các category. Mһc dù chӍ có 2 category có computer giá dưӟi
$2,000 nhưng vүn get tҩt cҧ các category. (Có lӁ có khoҧng 1,000,000 chӫng loҥi.) Và điӅu này sӁ trӣ
thành vҩn đӅ không thӇ bӓ qua vӅ mһt hiӋu suҩt thӵc hiӋn.

NӃu chúng ta mô tҧ câu lӋnh SELECT chӍ get nhӳng category có computer giá dưӟi $2,000 thì có thӇ giҧi
quyӃt đưӧc vҩn đӅ này. Chúng ta sӁ xem xét theo thӭ tӵ dưӟi đây.

Trưӟc tiên, vì chúng ta muӕn get category, nên lӋnh SELECT và lӋnh FROM sӁ phҧi như dưӟi đây.

select Category.Identity, Name, Description


from Category

Vì tôi muӕn viӃt Product.Price <= 2000 trong lӋnh WHERE nên tôi sӁ thӱ JOIN.

select
Category.Identity, Category.Name, Category.Description
from
Category
! ! 
 
 
!


 
!


Nhӡ đó mà đã có thӇ viӃt đưӧc cҧ lӋnh WHERE, nên tôi sӁ add thêm lӋnh WHERE.

select
Category.Identity, Category.Name, Category.Description
from
Category
inner join Product on Category.Identity = Product.CategoryIdentity
( 

! 

Tuy nhiên, nӃu dӵa vào câu lӋnh SQL này đӇ add thêm method vào TableAdapter, thì chúng ta sӁ hoàn
thành mӝt source code chưa thӇ chҥy đưӧc hoàn thiӋn. Sӣ dĩ như vұy là bӣi vì điӅu kiӋn tiӅn đӅ là phҧi
tӗn tҥi main key, mà DataTable nҵm trong DataSet không đưӧc phép bӏ trùng vӟi khóa chính đó. Vұy
chúng ta hãy cùng suy nghĩ. Trưӡng hӧp có ThinkPad T61 và ThinkPad X60S giá dưӟi $2,000 thì ӣ câu
lӋnh SQL lúc nãy sӁ trҧ vӅ kӃt quҧ như sau.

Category.Identity Category.Name
 Y 
 Y 

JOIN nghĩa là kӃt hӧp nhiӅu bҧng đӇ tҥo ra mӝt bҧng lӟn. WHERE nghĩa là chӑn trong bҧng dòng thӓa
mãn điӅu kiӋn. SELECT nghĩa là chӍ đӏnh cӝt sӁ output ra, do đó mà có kӃt quҧ như ӣ bҧng trên. ĐӅ giҧi
quyӃt vҩn đӅ này, tôi sӁ sӱ dөng DISTINCT vӕn là mӝt chӭc năng cӫa câu lӋnh SQL. DISTINCT là chӭc
năng tәng hӧp nhӳng row có nӝi dung giӕng nhau, nhӡ nó mà có thӇ tránh đưӧc tình trҥng main key bӏ
trùng. Dưӟi đây là câu lӋnh SQL cө thӇ.

select !
!

Category.Identity, Category.Name, Category.Description


from
Category
inner join Product on Category.Identity = Product.CategoryIdentity
where
Product.Price <= 2000.00

NӃu chúng ta sӱ dөng như trên, đӇ add thêm method FillByProductPriceBelow2000() vào
CategoryTableAdapter và viӃt lҥi *.aspx.cs như dưӟi đây thì chúng ta sӁ đưӧc đánh giá là có xem xét tӯ
tính bҧo trì đӃn hiӋu suҩt thӵc hiӋn mӝt cách toàn diӋn và có thӇ nhұn đưӧc order tiӃp theo.

public partial class UseTableAdapterWebForm : Page


{
private CatalogDataSet catalogDataSet;

protected CatalogDataSet CatalogDataSet


{
get { return catalogDataSet; }
set { catalogDataSet = value; }
}

protected void Page_Load(object sender, EventArgs e)


{
if (!IsPostBack)
{
// Tңo trưӟng hӥp (instance) cөa Typed-DataSet.
CatalogDataSet = new CatalogDataSet();

// Gӏi ra TableAdapter rӕi get data.


using (CatalogDataSetTableAdapters.CategoryTableAdapter ta = new
CatalogDataSetTableAdapters.CategoryTableAdapter())
{
ta.FillByProductPriceBelow2000(CatalogDataSet.Category);
}
using (CatalogDataSetTableAdapters.ProductTableAdapter ta = new
CatalogDataSetTableAdapters.ProductTableAdapter())
{
ta.FillByProductPriceBelow2000(CatalogDataSet.Product);
}

// Thӳc hiӉn data binding.


DataBind();
}
}
}

]#%
Business application sӁ đưӧc sӱa lҥi ngay cҧ sau khi đã hoҥt đӝng. Tính dӉ dàng chӍnh sӱa lҥi đưӧc gӑi
là tính bҧo trì. Và chúng ta không đưӧc phép deliver mӝt source code có tính bҧo trì thҩp.
ĐӇ nâng cao tính bҧo trì, điӅu quan trӑng là phҧi xóa bӓ sӵ trùng lһp. Do đó, sӁ rҩt hiӋu quҧ nӃu chúng
ta chia thành nhӳng nhóm class đơn giҧn có vai trò riêng lҿ. Nghĩa là, chúng ta không đưӧc ghi xӱ lý trao
đәi thông tin vӟi RDBMS vào event/handler cӫa Windows Form và Web Form. Phҧi chia xӱ lý trao đәi
thông tin vӟi RDBMS thành mӝt class riêng biӋt như là Data Access Logic Component. Và phương thӭc
sӱ dөng nguyên DataAdapter thưӡng thҩy trên tҥp chí và internet vì đưӧc viӃt mӝt cách tӵ do nên có
nhiӅu khҧ năng dүn đӃn viӋc viӃt xӱ lý trao đәi thông tin vӟi RDBMS vào trong event/handler.

TableAdapter là chӭc năng sinh tӵ đӝng Data Access Logic Component bҵng Visual Studio 2005.
TableAdapter có 2 ưu điӇm là: ³do tҥo tӵ đӝng nên chi phí cҫn thiӃt cho viӋc thӵc hiӋn thҩp´, và ³Data
Access Logic Component sӁ đưӧc bҳt buӝc phân chia thành các class riêng biӋt là TableAdapter´. Vì vӯa
đơn giҧn lҥi có thӇ nâng cao tính maintenance nên cҫn phҧi sӱ dөng TableAdapter trong phát triӇn
business application.

whi get table cha bҵng điӅu kiӋn tìm kiӃm cӫa table con thì không đưӧc quên viӋc phҧi sӱ dөng
DISTINCT đӇ không phát sinh trùng lһp các main key.

Potrebbero piacerti anche