一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - ASP.NET教程 - 在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝

2020-01-10 15:37heker2007 ASP.NET教程

事務(wù)的最主要的一個作用就是保證數(shù)據(jù)的完整性,本文主要介紹ASP.NET 2.0中使用事務(wù)對修改數(shù)據(jù)進(jìn)行封裝,這些包含事務(wù)的命令要么都執(zhí)行成功要么都執(zhí)行失敗。

導(dǎo)言:

  正如我們在第16章《概述插入、更新和刪除數(shù)據(jù)》里探討的那樣,GridView控件內(nèi)建的功能支持對每行數(shù)據(jù)的編輯和刪除功能,你只需要稍稍動一下鼠標(biāo)就可以創(chuàng)建豐富的數(shù)據(jù)修改界面而不用寫一行代碼.但是,在某些情況下,這還不夠,我們需要讓用戶能夠成批地處理數(shù)據(jù).

  比如,很多基于web(web-based)的電子郵件客戶端,將所有郵件出來,每條郵件除了包含郵件信息(主題、發(fā)送者等)外,還包含一個checkbox控件。這些界面允許用戶同時刪除多個郵件,用戶只需要選中郵件,再點"刪除所選郵件"按鈕.當(dāng)用戶要編輯多條不同的記錄的時候,提供一個批編輯界面是比較理想的.我們用不著讓用戶每次都選中一條要編輯的記錄,再做相關(guān)的修改,最后點“更新”按鈕,在批編輯界面里每條記錄都有各自的編輯選項,用戶可以快速地編輯多條記錄再點“Update All”按鈕來保存對他們所做的修改.本系列我們將考察如何創(chuàng)建對數(shù)據(jù)進(jìn)行添加、編輯、刪除批處理的界面.

  如果想對批處理執(zhí)行atomic operation(原子操作), 那么首先,所做的操作要么都執(zhí)行成功要么都失敗,另外還要對數(shù)據(jù)訪問層進(jìn)行擴(kuò)充以支持database transactions(數(shù)據(jù)庫事務(wù))。數(shù)據(jù)庫事務(wù)確保INSERT, UPDATE, 和 DELETE語句執(zhí)行的atomicity(原子數(shù))置于數(shù)據(jù)庫事務(wù)的保護(hù)之下.另外,絕大多數(shù)的當(dāng)代數(shù)據(jù)庫系統(tǒng)都支持?jǐn)?shù)據(jù)庫事務(wù).

  在本系列我們先看如何擴(kuò)充數(shù)據(jù)訪問層以支持?jǐn)?shù)據(jù)庫事務(wù),接下來我們看如何創(chuàng)建頁面以包含添加、更新、刪除數(shù)據(jù)的批處理界面,讓我們開始吧.

  注意:在批處理事務(wù)里修改數(shù)據(jù)時,原子數(shù)(atomicity)并非總數(shù)必要的。在批處理的某些情況下,某些修改成功某些修改失敗是可以接受的。比如刪除電子郵件時,有些郵件在刪除過程中發(fā)生了數(shù)據(jù)庫錯誤,有些郵件沒有發(fā)生錯誤,對這種沒有發(fā)生錯誤的郵件,批處理照樣將其刪除掉.對這種情況,我們沒有必要設(shè)置數(shù)據(jù)訪問層DAL支持?jǐn)?shù)據(jù)庫事務(wù).不過在其它某些情況下,原子數(shù)是至關(guān)重要的.比如某個客戶想把資金從一個銀行帳戶轉(zhuǎn)移到另一個銀行帳號,下面2個操作必須執(zhí)行成功:首先,將第一個帳號的資金扣除,然后將資金轉(zhuǎn)入第二個帳號.如果第一步執(zhí)行成功,第二步執(zhí)行失敗,銀行當(dāng)然高興,客戶怕是要發(fā)瘋了.在后面的文章里我們將創(chuàng)建添加、更新、刪除的批處理界面,就算你不打算在這些頁面里使用數(shù)據(jù)庫事務(wù),我也希望你照著本篇文章,對數(shù)據(jù)訪問層進(jìn)行擴(kuò)展一支持?jǐn)?shù)據(jù)庫事務(wù).

事務(wù)概述

絕大多數(shù)的數(shù)據(jù)庫都支持事務(wù),它可以將多個數(shù)據(jù)庫命令當(dāng)成一個邏輯單位進(jìn)行處理.這些包含事務(wù)的命令要么都執(zhí)行成功要么都執(zhí)行失敗.

一般來說,事務(wù)通過SQL命令來執(zhí)行,使用如下的模式:

1.聲明事務(wù)開始
2.執(zhí)行構(gòu)成事務(wù)的那些SQL命令
3.如果在第二步中的任何一個命令出錯,執(zhí)行事務(wù)回滾(rollback the transaction)
4.如果在第二步中的所有命令成功執(zhí)行,提交事務(wù)

  這些SQL命令可以通過手寫的方式輸入,比如寫SQL腳本、創(chuàng)建存儲過程、也可以通過編程的方式來構(gòu)建,比如使用ADO.NET技術(shù)或調(diào)用System.Transactions namespace命名空間的類.在本文,我們僅僅考察用ADO.NET技術(shù)管理事務(wù).在后面的教程我們看如何在數(shù)據(jù)訪問層Data Access Layer里使用存儲過程,到那時,我們再來考察這些創(chuàng)建、回滾、提交事物的SQL命令。另外,要獲得更多信息請參考文章《Managing Transactions in SQL Server Stored Procedures》(http://www.4guysfromrolla.com/webtech/080305-1.shtml)

  注意:System.Transactions namespace命名空間的TransactionScope class類允許開發(fā)者通過編程的方式獲取事務(wù)里的一系列命令,且允許事務(wù)包含多個數(shù)據(jù)源,甚至類型不同,比如:Microsoft SQL Server database, 或Oracle database,甚至Web service.本教程我們使用ADO.NET技術(shù)而非TransactionScope class類,是因為ADO.NET指定數(shù)據(jù)庫事務(wù)更詳細(xì),且在很多情況下占用資源更少.此外,在某些情況下,TransactionScope class類要用到Microsoft Distributed Transaction Coordinator (MSDTC),圍繞MSDTC的配置、執(zhí)行和性能問題是比較專業(yè)、高級的問題稍微超出了本教程的范圍.

  在ADO.NET里,通過調(diào)用SqlConnection class類的BeginTransaction method方法啟動事務(wù), 該方法返回一個SqlTransaction object對象.將構(gòu)成事務(wù)的數(shù)據(jù)操作命令放在try...catch區(qū)域,如果在try區(qū)域的某個命令出錯的話,程序?qū)⑥D(zhuǎn)到catch區(qū)域,在此,通過SqlTransaction object對象的Rollback method方法執(zhí)行事務(wù)回滾。如果所有的命令執(zhí)行成功,將調(diào)用位于try區(qū)域底部的SqlTransaction object對象的Commit method方法來提交事務(wù).下面的代碼片段揭示了該模式。要想看在ADO.NET里使用事務(wù)的更多例子,請參閱文章《Maintaining Database Consistency with Transactions》(http://aspnet.4guysfromrolla.com/articles/072705-1.aspx).

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Create the SqlTransaction object
SqlTransaction myTransaction = SqlConnectionObject.BeginTransaction();
 
try
{
 /*
 * ... Perform the database transaction's data modification statements...
 */
 
 // If we reach here, no errors, so commit the transaction
 myTransaction.Commit();
}
catch
{
 // If we reach here, there was an error, so rollback the transaction
 myTransaction.Rollback();
 
 throw;
}

  默認(rèn)情況下,強(qiáng)類型數(shù)據(jù)集(Typed DataSet)里的TableAdapters并不使用事務(wù)。為此,我們要對TableAdapter classes類進(jìn)行擴(kuò)展,以包含額外的方法以使用上述模式來執(zhí)行事務(wù)。在第二步,我們看如何使用一個partial classes類來添加這些方法.

第一步:創(chuàng)建批處理數(shù)據(jù)的頁面

  在我們考察如何擴(kuò)展數(shù)據(jù)訪問層DAL以支持?jǐn)?shù)據(jù)庫事務(wù)之前,讓我們花點時間來創(chuàng)建一些ASP.NET web頁面,我們在本章及后面三章將用到它們.

添加一個名為BatchData的新文件夾,再添加如下的 ASP.NET頁面, 務(wù)必套用Site.master模板頁.

Default.aspx
Transactions.aspx
BatchUpdate.aspx
BatchDelete.aspx
BatchInsert.aspx

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖1:添加相關(guān)的頁面

就像其它文件夾里的Default.aspx頁面一樣,用SectionLevelTutorialListing.ascx用戶控件來列出本部分的章節(jié)。將其從解決資源管理器里拖到Default.aspx頁面.

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖2:將SectionLevelTutorialListing.ascx用戶控件添加到Default.aspx頁面

最后添加如下代碼到Web.sitemap文件,具體的,將其添加到“Customizing the Site Map” <siteMapNode>后面:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<siteMapNode title="Working with Batched Data"
 url="~/BatchData/Default.aspx"
 description="Learn how to perform batch operations as opposed to
  per-row operations.">
 
 <siteMapNode title="Adding Support for Transactions"
 url="~/BatchData/Transactions.aspx"
 description="See how to extend the Data Access Layer to support
  database transactions." />
 <siteMapNode title="Batch Updating"
 url="~/BatchData/BatchUpdate.aspx"
 description="Build a batch updating interface, where each row in a
  GridView is editable." />
 <siteMapNode title="Batch Deleting"
 url="~/BatchData/BatchDelete.aspx"
 description="Explore how to create an interface for batch deleting
  by adding a CheckBox to each GridView row." />
 <siteMapNode title="Batch Inserting"
 url="~/BatchData/BatchInsert.aspx"
 description="Examine the steps needed to create a batch inserting
  interface, where multiple records can be created at the
  click of a button." />
</siteMapNode>

完成后,花幾分鐘在瀏覽器里登錄頁面,左面的菜單列出了本部分的各項

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖3:Site Map現(xiàn)在包含了本章節(jié)

第二步:更新數(shù)據(jù)訪問層以支持?jǐn)?shù)據(jù)庫事務(wù)

  就像我們在第一章《創(chuàng)建一個數(shù)據(jù)訪問層》探討的一樣,位于數(shù)據(jù)訪問層的強(qiáng)類型數(shù)據(jù)集(Typed DataSet)由DataTables 和 TableAdapters構(gòu)成.  DataTables保存數(shù)據(jù),而TableAdapters提供相應(yīng)的方法從數(shù)據(jù)庫讀取數(shù)據(jù),并根據(jù)DataTables的改動對數(shù)據(jù)庫做相應(yīng)的更新,等等.記得TableAdapters有2種更新數(shù)據(jù)的模式——Batch Update 和 DB-Direct.就Batch Update模式而言, TableAdapter可以傳入DataSet, DataTable, 或DataRows集,遍歷這些數(shù)據(jù)對要添加、修改、刪除的行執(zhí)行相應(yīng)的InsertCommand, UpdateCommand, or DeleteCommand方法。就DB-Direct模式而言,TableAdapter傳入的是那些需要進(jìn)行添加、更新、刪除操作的某條記錄的列的值,再使用這些值執(zhí)行相關(guān)的InsertCommand, UpdateCommand, 或DeleteCommand命令.

  TableAdapter自動生成的方法并不使用事務(wù).默認(rèn)狀態(tài)下,TableAdapter執(zhí)行的每一個insert, update, 或delete操作都看作是單獨的、互不相干的.假定在業(yè)務(wù)邏輯層BLL里使用DB-Direct模式來向數(shù)據(jù)庫添加十條記錄,代碼將分十次調(diào)用TableAdapter的Insert方法. 如果前5條記錄添加正常,而在添加第六條記錄時發(fā)生異常,前5條記錄仍然保存在數(shù)據(jù)庫.同樣的,用Batch Update模式來操作的話,效果亦然.

  在某些情況下,我們想確保在進(jìn)行一系列的改動時引入原子數(shù)(atomicity).為此,我們必須手動擴(kuò)展TableAdapter,通過添加一些新的方法將InsertCommand, UpdateCommand, 和DeleteCommands命令置于事務(wù)之下.在第一章《創(chuàng)建一個數(shù)據(jù)訪問層》里,我們考察了使用部分類(partial classes)對強(qiáng)類型數(shù)據(jù)集(Typed DataSet)里的DataTable的函數(shù)進(jìn)行擴(kuò)充.該技術(shù)同樣適用于TableAdapter.

  強(qiáng)類型數(shù)據(jù)集Northwind.xsd位于App_Code文件夾的DAL子文件夾里.在DAL文件夾里再創(chuàng)建一個名為TransactionSupport的子文件夾,再在里面添加一個新類,名為ProductsTableAdapter.TransactionSupport.cs (見圖4).該類包含ProductsTableAdapter的使用事務(wù)的方法.

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖4:創(chuàng)建一個名為TransactionSupport的新文件夾并添加一個名為ProductsTableAdapter.TransactionSupport.cs的新類

在ProductsTableAdapter.TransactionSupport.cs文件里鍵入如下的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
 
namespace NorthwindTableAdapters
{
 public partial class ProductsTableAdapter
 {
 private SqlTransaction _transaction;
 private SqlTransaction Transaction
 {
 get
 {
 return this._transaction;
 }
 set
 {
 this._transaction = value;
 }
 }
 
 
 public void BeginTransaction()
 {
 // Open the connection, if needed
 if (this.Connection.State != ConnectionState.Open)
 this.Connection.Open();
 
 // Create the transaction and assign it to the Transaction property
 this.Transaction = this.Connection.BeginTransaction();
 
 // Attach the transaction to the Adapters
 foreach (SqlCommand command in this.CommandCollection)
 {
 command.Transaction = this.Transaction;
 }
 
 this.Adapter.InsertCommand.Transaction = this.Transaction;
 this.Adapter.UpdateCommand.Transaction = this.Transaction;
 this.Adapter.DeleteCommand.Transaction = this.Transaction;
 }
 
 
 public void CommitTransaction()
 {
 // Commit the transaction
 this.Transaction.Commit();
 
 // Close the connection
 this.Connection.Close();
 }
 
 
 public void RollbackTransaction()
 {
 // Rollback the transaction
 this.Transaction.Rollback();
 
 // Close the connection
 this.Connection.Close();
 }
 }
}

  類聲明里的關(guān)鍵字partial向編譯器表明代碼里添加的成員(members)是添加到命名空間NorthwindTableAdapters里的ProductsTableAdapter class類.我們注意到在文件的頂部有一個using System.Data.SqlClient聲明,這是因為TableAdapter被設(shè)置為使用SqlClient provider,在其內(nèi)部使用一個SqlDataAdapter object對象來向數(shù)據(jù)庫發(fā)出命令.因此,我們需要使用SqlTransaction class類來啟動事務(wù),然后提交或回滾事務(wù).如果沒有使用Microsoft SQL Server數(shù)據(jù)庫的話,你需要調(diào)用恰當(dāng)?shù)膒rovider.

  這些方法被標(biāo)記為public,我們可以在ProductsTableAdapter里,或數(shù)據(jù)訪問層DAL的其它類,甚至是其它層比如業(yè)務(wù)邏輯層BLL來調(diào)用這些法.
BeginTransaction()方法打開了TableAdapter的內(nèi)部的SqlConnection(如果需要的話), 開啟事務(wù)并賦值給Transaction屬性,并將事務(wù)分配(attache)給SqlDataAdapter的SqlCommand objects對象.CommitTransaction()和 RollbackTransaction()方法在關(guān)閉內(nèi)部的Connection object對象前分別調(diào)用Transaction object對象的Commit 和 Rollback方法.

  添加上述代碼后,我們將在ProductsDataTable 或業(yè)務(wù)邏輯層BLL里添加方法以執(zhí)行一系列的置于事務(wù)之下的命令. 下面的代碼在Batch Update pattern模式里使用一個事務(wù)來更新一個ProductsDataTable instance實例.它調(diào)用BeginTransaction method方法來啟動一個事務(wù),然后用一個try...catch模塊來發(fā)布數(shù)據(jù)更改命令.如果調(diào)用Adapter object對象的Update方法出現(xiàn)異常,那么將轉(zhuǎn)到catch區(qū)域,對事務(wù)進(jìn)行回滾.記得執(zhí)行Batch Update pattern模式的Update方法將遍歷ProductsDataTable里的所有行(rows),執(zhí)行相應(yīng)的InsertCommand, UpdateCommand, 和DeleteCommands命令.如果這些命令中的其中一個出現(xiàn)異常,事務(wù)將回滾,撤銷在事務(wù)里的所做的更改.如果Update命令全部執(zhí)行無異常,那么提交事務(wù).

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public int UpdateWithTransaction(Northwind.ProductsDataTable dataTable)
{
 this.BeginTransaction();
 
 try
 {
 // Perform the update on the DataTable
 int returnValue = this.Adapter.Update(dataTable);
 
 // If we reach here, no errors, so commit the transaction
 this.CommitTransaction();
 
 return returnValue;
 }
 catch
 {
 // If we reach here, there was an error, so rollback the transaction
 this.RollbackTransaction();
 
 throw;
 }
}

  將上述的UpdateWithTransaction()方法添加到文件ProductsTableAdapter.TransactionSupport.cs里的ProductsTableAdapter class類。另外,還可以將該方法添加到業(yè)務(wù)邏輯層的ProductsBLL class類,不過要做些許修改:即將this.BeginTransaction(), this.CommitTransaction(), and this.RollbackTransaction()三中方法里的關(guān)鍵字“this”替換為“Adapter”(我們知道,ProductsBLL類里的ProductsTableAdapter的name屬性即是Adapter).

  UpdateWithTransaction()方法使用的是Batch Update模式,不過也可在事務(wù)里調(diào)用DB-Direct模式,就像下面的代碼顯示的那樣.DeleteProductsWithTransaction()方法接受一個int類型的List<T>,也就是要刪除的ProductIDs.該方法通過調(diào)用BeginTransaction來啟動事務(wù),然后在try模塊里對每一個ProductID值調(diào)用DB-Direct模式的Delete方法.如果任何一個對Delete的調(diào)用出錯,將轉(zhuǎn)到catch 模塊,事務(wù)將會回滾;如果所有對Delete的調(diào)用成功,那就提交事務(wù)。添加該方法給ProductsBLL class類.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public void DeleteProductsWithTransaction
 (System.Collections.Generic.List<int> productIDs)
{
 // Start the transaction
 Adapter.BeginTransaction();
 
 try
 {
 // Delete each product specified in the list
 foreach (int productID in productIDs)
 {
 Adapter.Delete(productID);
 }
 
 // Commit the transaction
 Adapter.CommitTransaction();
 }
 catch
 {
 // There was an error - rollback the transaction
 Adapter.RollbackTransaction();
 
 throw;
 }
}

在多個TableAdapters應(yīng)用事務(wù)

  到目前為止我們考察的是對ProductsTableAdapter里的多個命令采用原子操作.如果我們是對多個不同的數(shù)據(jù)庫表進(jìn)行改動,并對這些改動執(zhí)行原子操作那又怎么辦呢?比如:當(dāng)刪除一個category時,在刪除之前我們想把該種類對應(yīng)的products分配給其它的category.對這種2步操作——分配products和刪除category——應(yīng)該執(zhí)行原子操作.但是ProductsTableAdapter只包含修改Products表的方法;而CategoriesTableAdapter只包含修改Categories表的方法.那么怎樣使用一個包含這2個TableAdapters的事務(wù)呢?

  其中一個辦法是向CategoriesTableAdapter添加一個名為DeleteCategoryAndReassignProducts(categoryIDtoDelete, reassignToCategoryID)的方法.再定義一個方法來調(diào)用一個存儲過程,使用事務(wù)來達(dá)到分配products和刪除category的目的.我們將在后面考察在一個存儲過程里開始、提交和回滾事務(wù).

  另一個方法是在數(shù)據(jù)訪問層里添加一個類,來包含DeleteCategoryAndReassignProducts(categoryIDtoDelete, reassignToCategoryID)方法.該方法創(chuàng)建CategoriesTableAdapter 和 the ProductsTableAdapter的實例,并將這2個TableAdapters的Connection屬性設(shè)置為相同的SqlConnection實例。這樣,它們都將調(diào)用BeginTransaction來開啟事務(wù).然后在try...catch模塊里執(zhí)行分配products和刪除category的方法,最后提交或回滾事務(wù).

第四步:向業(yè)務(wù)邏輯層添加UpdateWithTransaction方法

  在第三步我們向數(shù)據(jù)訪問層DAL里的ProductsTableAdapter添加了一個UpdateWithTransaction方法,我們將向業(yè)務(wù)邏輯層添加相應(yīng)的方法.雖然表現(xiàn)層可以直接向DAL調(diào)用UpdateWithTransaction方法,但是我們在這里仍然將它們分隔開。

  打開ProductsBLL class類,添加一個名為UpdateWithTransaction的方法,該方法僅僅簡單地調(diào)用對應(yīng)的DAL方法.現(xiàn)在ProductsBLL類里有2個方法:UpdateWithTransaction方法——我們才添加的;以及DeleteProductsWithTransaction——我們在第三步添加的.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public int UpdateWithTransaction(Northwind.ProductsDataTable products)
{
 return Adapter.UpdateWithTransaction(products);
}
 
 
public void DeleteProductsWithTransaction
 (System.Collections.Generic.List<int> productIDs)
{
 // Start the transaction
 Adapter.BeginTransaction();
 
 try
 {
 // Delete each product specified in the list
 foreach (int productID in productIDs)
 Adapter.Delete(productID);
 
 // Commit the transaction
 Adapter.CommitTransaction();
 }
 catch
 {
 // There was an error - rollback the transaction
 Adapter.RollbackTransaction();
 
 throw;
 }
}

  注意:根ProductsBLL類里的大部分方法不同,上述方法并不包含DataObjectMethodAttribute屬性。這是因為我們將直接在ASP.NET頁面的后臺代碼里調(diào)用這些方法,記得DataObjectMethodAttribute方法的作用是指出哪些方法應(yīng)該出現(xiàn)在ObjectDataSource控件的設(shè)置數(shù)據(jù)源向?qū)У哪承?biāo)簽(SELECT, UPDATE, INSERT, 或DELETE)里.由于GridView控件缺乏內(nèi)置的支持“批編輯”或“批刪除”的功能,我們將通過編輯的方式來調(diào)用這些方法.

第五步:在表現(xiàn)層更新數(shù)據(jù)庫數(shù)據(jù)

  為演示更新一批記錄時事務(wù)的作用,我們將創(chuàng)建一個用戶界面來將所有產(chǎn)品用一個GridView控件顯示出來,并包含一個Button Web控件。當(dāng)點擊該按鈕時為product重新賦值一個有效的CategoryID值。具體來說,對頭幾個products分配一個有效的CategoryID值;而剩下的分配一個無效的(non-existent)CategoryID值,當(dāng)我們試圖對這樣的一個product——其CategoryID值與現(xiàn)有的category的CategoryID不匹配——進(jìn)行更新時,將違反外鍵約束,進(jìn)而拋出一個異常.在本文的示例里你將看到,在使用事務(wù)時,當(dāng)違反外鍵約束拋出一個異常時將導(dǎo)致前面的正確分配CategoryID值的操作產(chǎn)生回滾.如果不使用事務(wù)的話,這些正確的操作將執(zhí)行成功.

  首先,打開BatchData文件夾里的Transactions.aspx頁面,從工具箱拖一個GridView控件到頁面。設(shè)置其ID為Products,從其智能標(biāo)簽里將其綁定到一個名為ProductsDataSource的ObjectDataSource控件,設(shè)置該控件調(diào)用ProductsBLL class類的GetProducts()方法。由于該GridView是“只讀”的,在UPDATE, INSERT, 和DELETE標(biāo)簽里選“(None)”,點完成。

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖5:設(shè)置ObjectDataSource使用ProductsBLL Class類的GetProducts方法

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖6:在UPDATE, INSERT, 和DELETE標(biāo)簽里選“(None)”

  完成設(shè)置后,Visual Studio將自動的添加BoundFields以及一個CheckBoxField,刪除ProductID, ProductName, CategoryID,和CategoryName以外的其它列;并且分別將ProductName 和 CategoryName列的HeaderText屬性重命名為“Product” 和 “Category”.在智能標(biāo)簽里啟用“分頁”功能.做完這些修改后,GridView 和 ObjectDataSource控件的聲明代碼看起來應(yīng)該和下面的差不多:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<asp:GridView ID="Products" runat="server" AllowPaging="True"
 AutoGenerateColumns="False" DataKeyNames="ProductID"
 DataSourceID="ProductsDataSource">
 <Columns>
 <asp:BoundField DataField="ProductID" HeaderText="ProductID"
 InsertVisible="False" ReadOnly="True"
 SortExpression="ProductID" />
 <asp:BoundField DataField="ProductName" HeaderText="Product"
 SortExpression="ProductName" />
 <asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
 SortExpression="CategoryID" />
 <asp:BoundField DataField="CategoryName" HeaderText="Category"
 SortExpression="CategoryName" />
 </Columns>
</asp:GridView>
 
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
 OldValuesParameterFormatString="original_{0}"
 SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>

  然后,在GridView控件上添加3個Button Web控件,設(shè)置第一個按鈕的Text屬性 為“Refresh Grid”;第二個按鈕的Text屬性為“Modify Categories (WITH TRANSACTION)”;第三個按鈕的Text屬性為“Modify Categories (WITHOUT TRANSACTION)”.

 

?
1
2
3
4
5
6
7
8
9
10
11
<p>
 <asp:Button ID="RefreshGrid" runat="server" Text="Refresh Grid" />
</p>
<p>
 <asp:Button ID="ModifyCategoriesWithTransaction" runat="server"
 Text="Modify Categories (WITH TRANSACTION)" />
</p>
<p>
 <asp:Button ID="ModifyCategoriesWithoutTransaction" runat="server"
 Text="Modify Categories (WITHOUT TRANSACTION)" />
</p>


此時,在Visual Studio的設(shè)計模式里,界面看起來和下面的截屏差不多:

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖7:頁面包含一個GridView控件和三個Button Web控件

為這3個按鈕的Click events事件創(chuàng)建事件處理器,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
protected void RefreshGrid_Click(object sender, EventArgs e)
{
 Products.DataBind();
}
 
protected void ModifyCategoriesWithTransaction_Click(object sender, EventArgs e)
{
 // Get the set of products
 ProductsBLL productsAPI = new ProductsBLL();
 Northwind.ProductsDataTable products = productsAPI.GetProducts();
 
 // Update each product's CategoryID
 foreach (Northwind.ProductsRow product in products)
 {
 product.CategoryID = product.ProductID;
 }
 
 // Update the data using a transaction
 productsAPI.UpdateWithTransaction(products);
 
 // Refresh the Grid
 Products.DataBind();
}
 
protected void ModifyCategoriesWithoutTransaction_Click(object sender, EventArgs e)
{
 // Get the set of products
 ProductsBLL productsAPI = new ProductsBLL();
 Northwind.ProductsDataTable products = productsAPI.GetProducts();
 
 // Update each product's CategoryID
 foreach (Northwind.ProductsRow product in products)
 {
 product.CategoryID = product.ProductID;
 }
 
 // Update the data WITHOUT using a transaction
 NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
 new NorthwindTableAdapters.ProductsTableAdapter();
 productsAdapter.Update(products);
 
 // Refresh the Grid
 Products.DataBind();
}

 

  refresh按鈕的Click事件處理器僅僅調(diào)用Products GridView的DataBind方法將數(shù)據(jù)重新綁定到ridView控件.

  第二個事件處理器對products的CategoryID屬性重新賦值,并調(diào)用BLL層里的新的事務(wù)方法來執(zhí)行數(shù)據(jù)庫更新.我們注意到將每個產(chǎn)品的ProductID值賦給其CategoryID屬性,對最開頭的幾個產(chǎn)品而言沒有任何問題,但隨著ProductID值越變越大,CategoryID的值也越變越大,而Category表里定義的種類畢竟有限,于是問題就出來了。

  第三個事件處理器也是將ProductID值賦給CategoryID屬性,只是用ProductsTableAdapter的默認(rèn)的Update方法來更新數(shù)據(jù)庫. 該Update方法并沒有使用事務(wù)來封裝這些命令,所以只要是沒有違背外鍵約束的更新都會執(zhí)行成功.

  在瀏覽器里登錄該頁面進(jìn)行驗證.最開始你將看到如圖8所示的畫面,然后點“Modify Categories (WITH TRANSACTION)”.這將導(dǎo)致頁面回傳并試題更新所有products的CategoryID值,這將導(dǎo)致違背外鍵約束(見圖9).

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖8:Products將顯示在一個分頁的GridView控件里

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖9:導(dǎo)致違背外鍵約束

  現(xiàn)在點擊瀏覽器的Back按鈕,再點擊“Refresh Grid”按鈕,此時你看到的界面和圖8的界面一摸一樣。這是因為發(fā)生了違背外鍵約束,導(dǎo)致回滾,所有的操作失敗.

  再點“Modify Categories (WITHOUT TRANSACTION)”按鈕,這同樣將違背外鍵約束(見圖9),不過這一次,那些對CategoryID屬性賦以有效值的操作不會回滾.點擊瀏覽器的Back按鈕,再點“Refresh Grid”按鈕。就像圖10顯示的那樣,最開始的8個產(chǎn)品的CategoryID值已經(jīng)發(fā)生了更改,比如,在圖8里Chang的CategoryID值為1,而在圖10里就變成了2了.

在ASP.NET 2.0中操作數(shù)據(jù)之六十一:在事務(wù)里對數(shù)據(jù)庫修改進(jìn)行封裝
圖10:某些Product的CategoryID值發(fā)生了改變,而其它的沒有

結(jié)語:

  默認(rèn)情況下,TableAdapter的方法沒有使用事務(wù)來執(zhí)行數(shù)據(jù)庫命令,不過只需多做一點工作我們就可以添加一些用于創(chuàng)建、提交、回滾事務(wù)的方法.在本教程,我們在ProductsTableAdapter class類里創(chuàng)建了這3個方法:BeginTransaction, CommitTransaction,和RollbackTransaction.我們考察了如何在try...catch模塊里使用這些方法來執(zhí)行一系列的修改命令.具體來說,我們在ProductsTableAdapter里創(chuàng)建了UpdateWithTransaction方法,該方法運用Batch Update模式對ProductsDataTable里的每行記錄執(zhí)行必要的更改操作;我們也對BLL里的ProductsBLL class類添加了DeleteProductsWithTransaction方法,它將一系列ProductID值作為輸入?yún)?shù),并使用DB-Direct模式將每個產(chǎn)品刪除.這些方法開始都創(chuàng)建一個事務(wù),再在try...catch模塊里執(zhí)行數(shù)據(jù)更改命令.如果拋出異常,則回滾事務(wù),否則提交事務(wù).

  第五步演示了事務(wù)的作用。在接下來的3章我們將以本章為基礎(chǔ),創(chuàng)建批更新、批刪除、批添加的用戶界面.

  祝編程快樂!

作者簡介

  本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的書,是4GuysFromRolla.com的創(chuàng)始人,自1998年以來一直應(yīng)用 微軟Web技術(shù)。希望對大家的學(xué)習(xí)ASP.NET有所幫助。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产欧美日韩图片一区二区 | 色愉拍亚洲偷自拍 | 成人动漫在线免费看 | 美妇在男人胯下哀求 | 欧美怡红院视频一区二区三区 | 国产精品嫩草影院在线 | 日韩免费观看成第15集 | 美女bbxx美女bbb | 国产婷婷高清在线观看免费 | 九九九国产视频 | 成人看的羞羞视频免费观看 | 九九九好热在线 | 四虎私人影院 | 日韩欧美在线观看综合网另类 | 欧美日一级片 | 四虎免费在线观看 | 视频一区二区三区在线观看 | 亚洲高清一区二区三区四区 | 精品videoss另类日本 | 久久精品国产欧美日韩99热 | 教师波多野结衣在线播放 | 亚洲aⅴ男人的天堂在线观看 | 久久re亚洲在线视频 | 国产成人免费视频 | 金莲你下面好紧夹得我好爽 | yellow视频在线观看免费 | 四虎影库紧急大通知 | 乖女的嫩奶水h文孕妇 | 美女尿口羞羞视频 | 第一福利在线视频 | 蘑菇香蕉茄子绿巨人丝瓜草莓 | 国产主播福利在线观看 | 色啪久久婷婷综合激情 | 亚洲精品在线免费看 | 色综合天天综合网国产人 | 国产 国语对白 露脸正在播放 | 成人夜视频寂寞在线观看 | 亚洲精品国产乱码AV在线观看 | 精品国内自产拍在线视频 | 顶级欧美做受xxx000 | 欧美最猛性xxxxx动态图 |