DataSet 的 Merge 方法研究
2024-07-21 02:23:34
供稿:網(wǎng)友
在ado.net中我們在合并兩個相同或相近的dataset對象時,通常會使用dataset的merge方法,該方法有多個重載版本,在介紹它之前我們先復習merge方法,以下是msdn中對merge方法使用說明:
merge 方法用于合并架構大致相似的兩個 dataset 對象。合并在客戶端應用程序上通常用于將數(shù)據(jù)源中最近的更改合并到現(xiàn)有的 dataset 中。這使客戶端應用程序能夠擁有用數(shù)據(jù)源中的最新數(shù)據(jù)刷新的 dataset。通常在一系列過程的末尾調(diào)用 merge 方法,這些過程涉及驗證更改、消除錯誤、使用更改更新數(shù)據(jù)源并最后刷新現(xiàn)有的 dataset。
在客戶端應用程序中,通常有這樣一個按鈕,用戶可以單擊它來收集已更改的數(shù)據(jù)并對其進行驗證,然后將其發(fā)送回中間層組件。在這種情況下,將首先調(diào)用 getchanges 方法。該方法返回另一個為驗證和合并而優(yōu)化的 dataset。第二個 dataset 對象只包含已更改的 datatable 和 datarow 對象,結果產(chǎn)生初始 dataset 的子集。該子集通常較小,因此可以更有效率地傳遞回中間層組件。然后,中間層組件將通過存儲過程使用更改更新初始數(shù)據(jù)源。然后,中間層可以發(fā)送回一個新的 dataset,其中包含數(shù)據(jù)源中的初始數(shù)據(jù)和最新數(shù)據(jù)(通過再次運行初始查詢);或者它可以發(fā)送回包含從數(shù)據(jù)源對其進行的所有更改的子集。(例如,如果數(shù)據(jù)源自動創(chuàng)建唯一主鍵值,則可以將這些值傳播回客戶端應用程序。)在哪一種情況下都可以使用 merge 方法將返回的 dataset 合并回客戶端應用程序的初始 dataset。
當將新的源 dataset 合并到目標中時,datarowstate 值為 unchanged、modified 或 deleted 的任何源行都會與具有同一主鍵值的目標行相匹配。datarowstate 值為 added 的源行將匹配主鍵值與新源行相同的新目標行。
根據(jù)以上說明,我們知道m(xù)erge方法在合并兩個數(shù)據(jù)集時,是以行的主鍵值為主要對比參照。這樣在向數(shù)據(jù)集添加新行時不會有任何問題,在修改了行且不修改主鍵值的情況下也不會有問題,但是在更改行時如果你修改了主鍵的值,那問題就來了…… 下面我們就舉例說明:
在sql server下的一個products表結構如下:
列名
數(shù)據(jù)類型
說明
code
nchar
產(chǎn)品代碼(主鍵列)
name
nvarchar
產(chǎn)名名稱
unitprice
numeric
產(chǎn)品單價
在.net中使用xsd生成一個對應的productsdata.xsd結構如下:
列名
數(shù)據(jù)類型
說明
code
string
產(chǎn)品代碼(主鍵列)
name
string
產(chǎn)名名稱
unitprice
decimal
產(chǎn)品單價
根據(jù)msdn的說明,我們在前臺通過productsdata添加或修改數(shù)據(jù)后在提交后臺更新時,通常做法如下:
// 創(chuàng)建一個新數(shù)據(jù)集來保存對主數(shù)據(jù)集所做的更改
productsdata datasetchanges;
datasetchanges = (productsdata)(productsdata.getchanges());
// 檢查是否做了任何更改
if(datasetchanges != null) {
try {
// 需要做一些更改,所以嘗試通過調(diào)用 update 方法
// 和傳遞數(shù)據(jù)集以及任何參數(shù)來更新數(shù)據(jù)源
updatedatasource(datasetchanges);
productsdata.merge(datasetchanges);
productsdata.acceptchanges();
}
catch (system.exception eupdate) {
throw eupdate;
}
}
以上代碼是根據(jù)vs.net的數(shù)據(jù)窗體生成向?qū)懙?,依?jù)以上代碼我們模擬向數(shù)據(jù)集添加一行數(shù)據(jù)并更新后的情況:
code
name
unitprice
1001
金砂朱古力
120.00
沒問題,下面我們修改這行數(shù)據(jù)再更新,這里我們把code改為1002,更新之后結果數(shù)據(jù)并沒有按我們預想的把原本行code列的值1001改為1002,而是添加了一行:
code
name
unitprice
1001
金砂朱古力
120.00
1002
金砂朱古力
130.00
注:通常情況下我們是很少更改主鍵值,但在代碼沒有被使用的情況下,一般是允許更改code的,特別是在系統(tǒng)實施的階段。
出現(xiàn)以上問題的原因其實不奇怪,按merge方法的原理,這一點也沒錯,但這是我們不希望的結果,怎么解決呢,難道不允許用戶更改主鍵,但好象不符合實際。怎么解決呢?
既然要用merge方法,那只有依m(xù)erge合并數(shù)據(jù)的原理去做,不讓改主鍵我們就不改主鍵,我們可以給前臺的productsdata的數(shù)據(jù)集加多一個額外的主鍵id列,并把它的autoincrement設為true,將原本的主鍵列code改為key列,至于后臺sql server中的源表不作任何修改,修改后如下:
列名
數(shù)據(jù)類型
說明
id
int
自動增長列 (主鍵)
code
string
產(chǎn)品代碼 (key 鍵)
name
string
產(chǎn)名名稱
unitprice
decimal
產(chǎn)品單價
經(jīng)這樣一改,由于id是自動一個自遞增列,我們并不去修改它的值,這樣我們就可以隨意更改 code 列的值了,merge 方法在合并數(shù)據(jù)時由于是依據(jù)id例進行比對所以也不會再出現(xiàn)前面加多一行的問題了。
后記:這是我寫的 blog 申請好之后寫的第一篇有關技術的文章,自已感覺寫的有點羅嗦,其實寫那么長有用的只是最后的幾行,這可能對那些.net高手們只是雕蟲小技,所以讓高手們見笑了。