Sdílet prostřednictvím


Zabalení úprav databáze do transakce (VB)

Scott Mitchell

Stáhnout PDF

Tento kurz je první ze čtyř, který se zabývá aktualizací, odstraňováním a vkládáním dávek dat. V tomto kurzu se dozvíte, jak databázové transakce umožňují provádět dávkové úpravy jako atomické operace, což zajišťuje, že buď všechny kroky proběhnou úspěšně, nebo všechny kroky selžou.

Úvod

Jak jsme viděli v kurzu Přehled vkládání, aktualizace a odstraňování dat , GridView poskytuje integrovanou podporu pro úpravy a odstraňování na úrovni řádků. Několika kliknutími myši je možné vytvořit bohaté rozhraní pro úpravy dat bez psaní řádku kódu, pokud se spokojíte s úpravami a odstraňováním na základě jednotlivých řádků. V určitých scénářích je to ale nedostatečné a musíme uživatelům poskytnout možnost upravit nebo odstranit dávku záznamů.

Například většina webových e-mailových klientů používá k výpisu každé zprávy mřížku, kde každý řádek obsahuje zaškrtávací políčko spolu s informacemi o e-mailu (předmět, odesílatel atd.). Toto rozhraní umožňuje uživateli odstranit více zpráv jejich zaškrtnutím a následným kliknutím na tlačítko Odstranit vybrané zprávy. Rozhraní pro dávkové úpravy je ideální v situacích, kdy uživatelé běžně upravují mnoho různých záznamů. Místo toho, aby uživatel nutí kliknout na Upravit, provést změny a potom kliknout na Aktualizovat pro každý záznam, který je potřeba upravit, vykreslí rozhraní dávkové úpravy každý řádek s jeho rozhraním pro úpravy. Uživatel může rychle změnit sadu řádků, které je třeba změnit, a pak tyto změny uložit kliknutím na tlačítko Aktualizovat vše. V této sadě kurzů prozkoumáme, jak vytvořit rozhraní pro vkládání, úpravy a odstraňování dávek dat.

Při provádění dávkových operací je důležité určit, jestli by některé operace v dávce měly být úspěšné, zatímco jiné selžou. Zvažte rozhraní pro dávkové odstranění – co by se mělo stát, když se první vybraný záznam úspěšně odstraní, ale druhý záznam selže, například kvůli porušení omezení cizího klíče? Mělo by být odstranění prvního záznamu vráceno zpět, nebo je přijatelné, aby první záznam zůstal odstraněný?

Pokud chcete, aby se dávková operace chovala jako atomická operace, kdy všechny kroky proběhnou úspěšně nebo všechny kroky selžou, je potřeba rozšířit vrstvu přístupu k datům tak, aby zahrnovala podporu databázových transakcí. Databázové transakce zaručují nedělitelnost pro sadu INSERTpříkazů , UPDATEa DELETE spouštěných v rámci transakce a jsou funkcí podporovanou většinou moderních databázových systémů.

V tomto kurzu se podíváme na to, jak rozšířit dal tak, aby používal databázové transakce. V dalších kurzech se podíváme na implementaci webových stránek pro dávkové vkládání, aktualizaci a odstraňování rozhraní. Pusťme se do toho!

Poznámka

Při úpravě dat v dávkové transakci není vždy potřeba nedělitelnost. V některých scénářích může být přijatelné, aby některé úpravy dat byly úspěšné a jiné ve stejné dávce selžou, například při odstranění sady e-mailů z webového e-mailového klienta. Pokud v průběhu procesu odstranění dojde k chybě databáze, je pravděpodobně přijatelné, aby tyto záznamy zpracované bez chyby zůstaly odstraněny. V takových případech není nutné upravovat dal pro podporu databázových transakcí. Existují ale i jiné scénáře dávkových operací, kde je nedělitelnost důležitá. Když zákazník přesune své prostředky z jednoho bankovního účtu na jiný, musí být provedeny dvě operace: prostředky musí být odečteny z prvního účtu a poté přidány k druhému účtu. I když bance nemusí vadit, že první krok uspěje, ale druhý krok selže, její zákazníci by se pochopitelně rozrušili. Doporučuji vám, abyste tento kurz propracovali a implementovali vylepšení dal pro podporu databázových transakcí i v případě, že neplánujete jejich použití v dávkovém vkládání, aktualizaci a odstraňování rozhraní, které budeme vytvářet v následujících třech kurzech.

Přehled transakcí

Většina databází zahrnuje podporu transakcí, které umožňují seskupit více databázových příkazů do jedné logické pracovní jednotky. Databázové příkazy, které tvoří transakci, jsou zaručeny atomické, což znamená, že buď všechny příkazy selžou, nebo všechny budou úspěšné.

Obecně platí, že transakce se implementují prostřednictvím příkazů SQL pomocí následujícího vzoru:

  1. Označuje začátek transakce.
  2. Spusťte příkazy SQL, které tvoří transakci.
  3. Pokud v jednom z příkazů z kroku 2 dojde k chybě, vraťte transakci zpět.
  4. Pokud se všechny příkazy z kroku 2 dokončí bez chyby, potvrďte transakci.

Příkazy SQL používané k vytvoření, potvrzení a vrácení transakce lze zadat ručně při psaní skriptů SQL nebo vytváření uložených procedur, nebo programově pomocí ADO.NET nebo tříd v System.Transactions oboru názvů. V tomto kurzu prozkoumáme pouze správu transakcí pomocí ADO.NET. V budoucím kurzu se podíváme na to, jak používat uložené procedury ve vrstvě přístupu k datům. V tomto okamžiku prozkoumáme příkazy SQL pro vytváření, vrácení zpět a potvrzování transakcí. Další informace mezitím najdete v tématu Správa transakcí v SQL Server uložených procedur.

Poznámka

TřídaTransactionScope v System.Transactions oboru názvů umožňuje vývojářům programově zabalit řadu příkazů v rámci transakce a zahrnuje podporu složitých transakcí, které zahrnují více zdrojů, jako jsou dvě různé databáze nebo dokonce heterogenní typy úložišť dat, jako je databáze Microsoft SQL Server, databáze Oracle a webová služba. Rozhodl(a) jsem se pro tento kurz TransactionScope místo třídy použít ADO.NET transakce, protože ADO.NET je konkrétnější pro databázové transakce a v mnoha případech je mnohem méně náročný na prostředky. Kromě toho v určitých scénářích TransactionScope třída používá MsDTC (Microsoft Distributed Transaction Coordinator). Problémy s konfigurací, implementací a výkonem nástroje MSDTC z něj činí poměrně specializované a pokročilé téma nad rámec těchto kurzů.

Při práci se zprostředkovatelem SqlClient v ADO.NET jsou transakce inicializovány prostřednictvím volání SqlConnection metody třídy sBeginTransaction, která vrací SqlTransaction objekt. Příkazy pro úpravu dat, které tvoří transakci, jsou umístěny v try...catch bloku. Pokud dojde k chybě v příkazu v try bloku, provádění se přenese do catch bloku, kde lze transakci vrátit zpět pomocí metody objektu SqlTransaction sRollback. Pokud se všechny příkazy úspěšně dokončí, volání metody objektu SqlTransaction s Commit na konci try bloku potvrdí transakci. Následující fragment kódu znázorňuje tento vzor.

' Create the SqlTransaction object
Dim myTransaction As SqlTransaction = 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
End Try

Ve výchozím nastavení TableAdapter v typed dataSet nepoužívají transakce. Chcete-li poskytnout podporu pro transakce, musíme rozšířit Třídy TableAdapter o další metody, které používají výše uvedený vzor k provedení řady příkazů změny dat v rámci rozsahu transakce. V kroku 2 se dozvíte, jak přidat tyto metody pomocí částečných tříd.

Krok 1: Vytvoření webové stránky práce s datovými stránkami v dávkách

Než začneme zkoumat, jak rozšířit dal o podporu databázových transakcí, udělejme si nejdřív chvilku a vytvořte ASP.NET webových stránek, které budeme potřebovat pro tento kurz a tři následující tři. Začněte přidáním nové složky s názvem BatchData a potom přidejte následující ASP.NET stránky, které přidružují každou stránku se stránkou Site.master předlohy.

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

Přidání stránek ASP.NET pro kurzy SqlDataSource-Related

Obrázek 1: Přidání stránek ASP.NET pro kurzy SqlDataSource-Related

Stejně jako u ostatních složek Default.aspx použije SectionLevelTutorialListing.ascx uživatelský ovládací prvek k zobrazení seznamu kurzů v jeho oddílu. Proto přidejte tento uživatelský ovládací prvek do Default.aspx přetažením z Průzkumník řešení do zobrazení Návrh stránky.

Přidání uživatelského ovládacího prvku SectionLevelTutorialListing.ascx do Default.aspx

Obrázek 2: Přidání SectionLevelTutorialListing.ascx uživatelského ovládacího prvku do Default.aspx (kliknutím zobrazíte obrázek v plné velikosti)

Nakonec přidejte tyto čtyři stránky jako položky do Web.sitemap souboru. Konkrétně přidejte následující kód za Přizpůsobení mapy <siteMapNode>webu:

<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>

Po aktualizaci Web.sitemapse chvíli podívejte na web kurzů prostřednictvím prohlížeče. Nabídka na levé straně teď obsahuje položky pro kurzy práce s daty v dávkách.

Mapa webu teď obsahuje položky pro kurzy Práce s daty v dávkách.

Obrázek 3: Mapa webu teď obsahuje položky pro kurzy Práce s daty v dávkách

Krok 2: Aktualizace vrstvy přístupu k datům pro podporu databázových transakcí

Jak jsme probírali v prvním kurzu Vytvoření vrstvy přístupu k datům, typová sada dat v dal se skládá z datových tabulek a objektů TableAdapter. DataTables uchovávají data, zatímco adaptéry TableAdapter poskytují funkce pro čtení dat z databáze do tabulek DataTables, aktualizaci databáze pomocí změn provedených v datových tabulkách atd. Vzpomeňte si, že objekty TableAdapter poskytují dva vzory pro aktualizaci dat, které jsem označil jako Dávková aktualizace a Db-Direct. Se vzorem Dávkové aktualizace se objektu TableAdapter předá dataSet, DataTable nebo kolekce DataRows. Tato data jsou vyčíslena a pro každý vložený, upravený nebo odstraněný řádek InsertCommandse spustí , UpdateCommandnebo DeleteCommand . Se vzorem DB-Direct se do pole TableAdapter předávají hodnoty sloupců, které jsou nezbytné pro vložení, aktualizaci nebo odstranění jednoho záznamu. Metoda DB Direct pattern pak použije tyto předané hodnoty ke spuštění příslušného InsertCommandpříkazu , UpdateCommandnebo DeleteCommand .

Bez ohledu na použitý vzor aktualizace, objekty TableAdapter automaticky generované metody nepoužívají transakce. Ve výchozím nastavení se každé vložení, aktualizace nebo odstranění provedené objektem TableAdapter považuje za jednu samostatnou operaci. Představte si například, že vzor DB-Direct používá nějaký kód v BLL k vložení deseti záznamů do databáze. Tento kód by desetkrát volal metodu TableAdapter s Insert . Pokud bylo prvních pět vložení úspěšné, ale šestá z nich způsobila výjimku, prvních pět vložených záznamů zůstane v databázi. Podobně platí, že pokud se k vložení, aktualizaci a odstranění řádků vložených, upravených a odstraněných řádků v tabulce DataTable použije vzor dávkové aktualizace, u prvních několika úprav uspělo, ale u pozdějších došlo k chybě, zůstanou tyto dřívější úpravy, které byly dokončeny, v databázi.

V určitých scénářích chceme zajistit nedělitelnost v řadě úprav. Chcete-li toho dosáhnout, musíme ručně rozšířit Objekt TableAdapter přidáním nových metod, které provádějí InsertCommand, UpdateCommanda DeleteCommand pod zastřešující transakce. V části Vytvoření vrstvy přístupu k datům jsme se podívali na použití částečných tříd k rozšíření funkcí datových tabulek v rámci typové datové sady. Tuto techniku lze použít také s tableAdaptery.

Typed DataSet Northwind.xsd se nachází v App_Code podsložce složky s DAL . Vytvořte ve DAL složce TransactionSupport podsložku a přidejte nový soubor třídy s názvem ProductsTableAdapter.TransactionSupport.vb (viz Obrázek 4). Tento soubor bude obsahovat částečnou implementaci ProductsTableAdapter , která obsahuje metody pro provádění úprav dat pomocí transakce.

Přidejte složku s názvem TransactionSupport a soubor třídy s názvem ProductsTableAdapter.TransactionSupport.vb

Obrázek 4: Přidání složky s názvem TransactionSupport a souboru třídy s názvem ProductsTableAdapter.TransactionSupport.vb

Do souboru zadejte následující kód ProductsTableAdapter.TransactionSupport.vb :

Imports System.Data
Imports System.Data.SqlClient
Namespace NorthwindTableAdapters
    Partial Public Class ProductsTableAdapter
        Private _transaction As SqlTransaction
        Private Property Transaction() As SqlTransaction
            Get
                Return Me._transaction
            End Get
            Set(ByVal Value As SqlTransaction)
                Me._transaction = Value
            End Set
        End Property
        Public Sub BeginTransaction()
            ' Open the connection, if needed
            If Me.Connection.State <> ConnectionState.Open Then
                Me.Connection.Open()
            End If
            ' Create the transaction and assign it to the Transaction property
            Me.Transaction = Me.Connection.BeginTransaction()
            ' Attach the transaction to the Adapters
            For Each command As SqlCommand In Me.CommandCollection
                command.Transaction = Me.Transaction
            Next
            Me.Adapter.InsertCommand.Transaction = Me.Transaction
            Me.Adapter.UpdateCommand.Transaction = Me.Transaction
            Me.Adapter.DeleteCommand.Transaction = Me.Transaction
        End Sub
        Public Sub CommitTransaction()
            ' Commit the transaction
            Me.Transaction.Commit()
            ' Close the connection
            Me.Connection.Close()
        End Sub
        Public Sub RollbackTransaction()
            ' Rollback the transaction
            Me.Transaction.Rollback()
            ' Close the connection
            Me.Connection.Close()
        End Sub
    End Class
End Namespace

Klíčové Partial slovo v deklaraci třídy zde označuje kompilátoru, že členy přidané v rámci mají být přidány do ProductsTableAdapter třídy v NorthwindTableAdapters oboru názvů. Všimněte si Imports System.Data.SqlClient příkazu v horní části souboru. Vzhledem k tomu, že objekt TableAdapter byl nakonfigurován tak, aby používal zprostředkovatele SqlClient, interně používá SqlDataAdapter objekt k vydávání příkazů do databáze. V důsledku toho musíme použít SqlTransaction třídu k zahájení transakce a pak ji potvrdit nebo vrátit zpět. Pokud používáte jiné úložiště dat než Microsoft SQL Server, budete muset použít příslušného poskytovatele.

Tyto metody poskytují stavební bloky potřebné ke spuštění, vrácení zpět a potvrzení transakce. Jsou označené , Publiccož umožňuje jejich použití v rámci ProductsTableAdapter, z jiné třídy v dal nebo z jiné vrstvy v architektuře, jako je BLL. BeginTransaction otevře interní SqlConnection objekt TableAdapter s (v případě potřeby), zahájí transakci a přiřadí ji vlastnosti Transaction a připojí transakci k interním SqlDataAdapter objektům s SqlCommand . CommitTransactiona RollbackTransaction před zavřením interního Connection objektu Transaction volejte metody objektu s Commit a Rollback metody.

Krok 3: Přidání metod pro aktualizaci a odstranění dat pod zastřešující transakce

Po dokončení těchto metod jsme připraveni přidat do ProductsDataTable nebo BLL metody, které provádějí řadu příkazů pod zastřešující transakci. Následující metoda používá model Batch Update k aktualizaci ProductsDataTable instance pomocí transakce. Spustí transakci voláním BeginTransaction metody a pak použije Try...Catch blok k vydání příkazů změny dat. Pokud volání metody objektu Adapter s Update způsobí výjimku, provádění se přenese do catch bloku, kde se transakce vrátí zpět a výjimka se znovu vyvolá. Vzpomeňte Update si, že metoda implementuje vzor Batch Update tak, že vyčíslí řádky zadaného ProductsDataTable a provede potřebné InsertCommand, UpdateCommanda DeleteCommand s. Pokud některý z těchto příkazů způsobí chybu, transakce se vrátí zpět a vrátí zpět předchozí změny provedené během životnosti transakce. Pokud se Update příkaz dokončí bez chyby, transakce se potvrdí v celém rozsahu.

Public Function UpdateWithTransaction _
    (ByVal dataTable As Northwind.ProductsDataTable) As Integer
    
    Me.BeginTransaction()
    Try
        ' Perform the update on the DataTable
        Dim returnValue As Integer = Me.Adapter.Update(dataTable)
        ' If we reach here, no errors, so commit the transaction
        Me.CommitTransaction()
        Return returnValue
    Catch
        ' If we reach here, there was an error, so rollback the transaction
        Me.RollbackTransaction()
        Throw
    End Try
End Function

Přidejte metodu UpdateWithTransactionProductsTableAdapter do třídy prostřednictvím částečné třídy v ProductsTableAdapter.TransactionSupport.vb. Případně lze tuto metodu přidat do třídy s vrstvy obchodní logiky ProductsBLL s několika drobnými syntaktickými změnami. Konkrétně by bylo potřeba nahradit klíčové slovo v , a (vzpomeňte Adapter si, že Adapter je to název vlastnosti typu ProductsBLLProductsTableAdapter).Me.RollbackTransaction()Me.CommitTransaction()Me.BeginTransaction()Me

Metoda UpdateWithTransaction používá vzor Batch Update, ale řadu DB-Direct volání lze použít také v rámci transakce, jak ukazuje následující metoda. Metoda DeleteProductsWithTransaction přijímá jako vstup List(Of T) typ Integer, což jsou ProductID hodnoty, které se mají odstranit. Metoda zahájí transakci voláním BeginTransaction a pak v Try bloku iteruje zadaným seznamem, který volá metodu DB-Direct vzor Delete pro každou ProductID hodnotu. Pokud se některé z volání nezdaří Delete , řízení se přenese do Catch bloku, kde je transakce vrácena zpět a výjimka se znovu vyvolá. Pokud jsou Delete všechna volání úspěšná, transakce je potvrzena. Přidejte tuto metodu do ProductsBLL třídy.

Public Sub DeleteProductsWithTransaction _
    (ByVal productIDs As System.Collections.Generic.List(Of Integer))
    
    ' Start the transaction
    Adapter.BeginTransaction()
    Try
        ' Delete each product specified in the list
        For Each productID As Integer In productIDs
            Adapter.Delete(productID)
        Next
        ' Commit the transaction
        Adapter.CommitTransaction()
    Catch
        ' There was an error - rollback the transaction
        Adapter.RollbackTransaction()
        Throw
    End Try
End Sub

Použití transakcí v několika tableadaptech

Kód související s transakcemi zkoumaný v tomto kurzu umožňuje, aby bylo více příkazů proti objektu ProductsTableAdapter považováno za atomické operace. Ale co když je potřeba provést více úprav různých databázových tabulek atomicky? Například při odstraňování kategorie můžeme napřed chtít znovu přiřadit její aktuální produkty k nějaké jiné kategorii. Tyto dva kroky opětovného přiřazení produktů a odstranění kategorie by měly být provedeny jako atomická operace. Ale zahrnuje ProductsTableAdapter pouze metody pro úpravu Products tabulky a CategoriesTableAdapter zahrnuje pouze metody pro úpravu Categories tabulky. Jak tedy může transakce zahrnovat oba TableAdaptery?

Jednou z možností je přidat metodu do pojmenované CategoriesTableAdapterDeleteCategoryAndReassignProducts(categoryIDtoDelete, reassignToCategoryID) a nechat tuto metodu volat uloženou proceduru, která znovu přiřazuje produkty a odstraní kategorii v rámci rozsahu transakce definovaného v rámci uložené procedury. V dalším kurzu se podíváme na to, jak zahájit, potvrdit a vrátit transakce v uložených procedurách.

Další možností je vytvořit pomocnou třídu v dal, která obsahuje metodu DeleteCategoryAndReassignProducts(categoryIDtoDelete, reassignToCategoryID) . Tato metoda vytvoří instanci objektu CategoriesTableAdapter a a ProductsTableAdapter pak nastaví tyto dvě vlastnosti TableAdapter Connection na stejnou SqlConnection instanci. V tomto okamžiku by jeden ze dvou objektů TableAdapter zahájil transakci voláním BeginTransaction. Metody TableAdapter pro opětovné přiřazení produktů a odstranění kategorie by byly vyvolány v Try...Catch bloku s transakcí potvrzenou nebo vrácenou zpět podle potřeby.

Krok 4: PřidáníUpdateWithTransactionmetody do vrstvy obchodní logiky

V kroku 3 jsme přidali metodu UpdateWithTransaction do ProductsTableAdapter souboru DAL. Do BLL bychom měli přidat odpovídající metodu. Zatímco prezentační vrstva by mohla volat přímo dolů dal vyvolat metodu UpdateWithTransaction , tyto kurzy se snažily definovat vrstvené architektury, která izoluje DAL od prezentační vrstvy. Proto se nám sluší pokračovat v tomto přístupu.

ProductsBLL Otevřete soubor třídy a přidejte metodu s názvemUpdateWithTransaction, která jednoduše volá odpovídající metodu DAL. V nástroji by teď měly být dvě nové metody ProductsBLL: UpdateWithTransaction, které jste právě přidali, a DeleteProductsWithTransaction, které byly přidány v kroku 3.

Public Function UpdateWithTransaction _
    (ByVal products As Northwind.ProductsDataTable) As Integer
    
    Return Adapter.UpdateWithTransaction(products)
End Function
Public Sub DeleteProductsWithTransaction _
    (ByVal productIDs As System.Collections.Generic.List(Of Integer))
    
    ' Start the transaction
    Adapter.BeginTransaction()
    Try
        ' Delete each product specified in the list
        For Each productID As Integer In productIDs
            Adapter.Delete(productID)
        Next
        ' Commit the transaction
        Adapter.CommitTransaction()
    Catch
        ' There was an error - rollback the transaction
        Adapter.RollbackTransaction()
        Throw
    End Try
End Sub

Poznámka

Tyto metody nezahrnují DataObjectMethodAttribute atribut přiřazený většině ostatních metod ve ProductsBLL třídě, protože tyto metody budeme vyvolat přímo z tříd kódu ASP.NET stránek. Vzpomeňte si, že DataObjectMethodAttribute se používá k označení, které metody by se měly zobrazit v průvodci ObjectDataSource s Konfigurací zdroje dat a na jaké kartě (SELECT, UPDATE, INSERT nebo DELETE). Vzhledem k tomu, že GridView nemá žádnou integrovanou podporu pro dávkové úpravy nebo odstraňování, budeme muset tyto metody vyvolat programově místo použití deklarativního přístupu bez kódu.

Krok 5: Atomická aktualizace dat databáze z prezentační vrstvy

Chcete-li ilustrovat účinek transakce při aktualizaci dávky záznamů, pojďme vytvořit uživatelské rozhraní, které obsahuje seznam všech produktů v GridView a obsahuje ovládací prvek Button Web, který po kliknutí znovu přiřazuje hodnoty produktů CategoryID . Konkrétně bude změna přiřazení kategorie probíhat tak, aby prvním několika produktům byla přiřazena platná CategoryID hodnota, zatímco jiným je účelově přiřazena neexistující CategoryID hodnota. Pokud se pokusíme databázi aktualizovat produktem, který CategoryID neodpovídá existující kategorii s CategoryID, dojde k porušení omezení cizího klíče a vyvolá se výjimka. V tomto příkladu uvidíme, že při použití transakce výjimka vyvolaná z porušení omezení cizího klíče způsobí vrácení předchozích platných CategoryID změn zpět. Pokud ale transakci nepoužíváte, změny počátečních kategorií zůstanou zachovány.

Začněte tím, že Transactions.aspx otevřete stránku ve BatchData složce a přetáhnete GridView z panelu nástrojů do Designer. Nastavte jeho ID hodnotu Products na a z inteligentní značky ji vytvořte vazbu k novému objektu ObjectDataSource s názvem ProductsDataSource. Nakonfigurujte ObjectDataSource tak, aby načítá data z ProductsBLL metody třídy s GetProducts . Toto bude objekt GridView jen pro čtení, takže nastavte rozevírací seznamy na kartách UPDATE, INSERT a DELETE na (Žádné) a klikněte na Dokončit.

Konfigurace ObjectDataSource na použití metody GetProducts třídy ProductsBLL

Obrázek 5: Konfigurace objektu ObjectDataSource pro použití ProductsBLL metody Třídy s GetProducts (kliknutím zobrazíte obrázek v plné velikosti)

Nastavte Drop-Down Seznamy na kartách UPDATE, INSERT a DELETE na (Žádné).

Obrázek 6: Nastavení Drop-Down Seznamy na kartách UPDATE, INSERT a DELETE na (Žádné) (Kliknutím zobrazíte obrázek v plné velikosti)

Po dokončení průvodce Konfigurací zdroje dat vytvoří Visual Studio pro pole dat produktu BoundFields a CheckBoxField. Odeberte všechna tato pole s výjimkou ProductID, ProductNameCategoryID, a CategoryName přejmenujte ProductName vlastnosti BoundFields HeaderTextCategoryName na Product (Produkt) a Category (Kategorie). U inteligentní značky zaškrtněte možnost Povolit stránkování. Po provedení těchto úprav by deklarativní značky GridView a ObjectDataSource měly vypadat takto:

<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>

Dále přidejte tři ovládací prvky Button Web nad GridView. Nastavte první vlastnost Text tlačítka na Aktualizovat mřížku, druhá vlastnost na Modify Categories (WITH TRANSACTION) a třetí vlastnost s na Modify Categories (WITHOUT TRANSACTION) .

<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>

V tomto okamžiku by návrhové zobrazení v sadě Visual Studio mělo vypadat podobně jako snímek obrazovky na obrázku 7.

Stránka obsahuje webové ovládací prvky GridView a Tři tlačítka.

Obrázek 7: Stránka obsahuje webové ovládací prvky GridView a Tři tlačítka (kliknutím zobrazíte obrázek v plné velikosti)

Vytvořte obslužné rutiny událostí pro každou ze tří událostí Button s Click a použijte následující kód:

Protected Sub RefreshGrid_Click _
    (ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles RefreshGrid.Click
    
    Products.DataBind()
End Sub
Protected Sub ModifyCategoriesWithTransaction_Click _
    (ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles ModifyCategoriesWithTransaction.Click
    
    ' Get the set of products
    Dim productsAPI As New ProductsBLL()
    Dim productsData As Northwind.ProductsDataTable = productsAPI.GetProducts()
    ' Update each product's CategoryID
    For Each product As Northwind.ProductsRow In productsData
        product.CategoryID = product.ProductID
    Next
    ' Update the data using a transaction
    productsAPI.UpdateWithTransaction(productsData)
    ' Refresh the Grid
    Products.DataBind()
End Sub
Protected Sub ModifyCategoriesWithoutTransaction_Click _
    (ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles ModifyCategoriesWithoutTransaction.Click
    
    ' Get the set of products
    Dim productsAPI As New ProductsBLL()
    Dim productsData As Northwind.ProductsDataTable = productsAPI.GetProducts()
    ' Update each product's CategoryID
    For Each product As Northwind.ProductsRow In productsData
        product.CategoryID = product.ProductID
    Next
    ' Update the data WITHOUT using a transaction
    Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
    productsAdapter.Update(productsData)
    ' Refresh the Grid
    Products.DataBind()
End Sub

Obslužná rutina události refresh Button s Click jednoduše znovu připojí data do Objekt GridView voláním Products metody GridView s DataBind .

Druhá obslužná rutina události znovu přiřazuje produkty CategoryID s a používá novou metodu transakce z BLL k provádění aktualizací databáze v rámci transakce. Všimněte si, že každý produkt s CategoryID je libovolně nastaven na stejnou hodnotu jako jeho ProductID. To bude fungovat dobře u několika prvních produktů, protože tyto produkty mají ProductID hodnoty, které se mapují na platné CategoryID s. Ale jakmile ProductID se s začnou příliš zvětšovat, toto náhodné překrytí ProductID s a CategoryID s už neplatí.

Třetí Click obslužná rutina události aktualizuje produkty CategoryID stejným způsobem, ale odešle aktualizaci do databáze pomocí ProductsTableAdapter výchozí Update metody s. Tato Update metoda nezabalí řadu příkazů v rámci transakce, takže tyto změny jsou provedeny dříve, než první zjištěná chyba narušení omezení cizího klíče zůstane zachována.

Pokud chcete toto chování předvést, navštivte tuto stránku v prohlížeči. Na začátku byste měli vidět první stránku dat, jak je znázorněno na obrázku 8. Potom klikněte na tlačítko Upravit kategorie (S TRANSAKCÍ). To způsobí postback a pokusí se aktualizovat všechny hodnoty produktů CategoryID , ale způsobí porušení omezení cizího klíče (viz obrázek 9).

Produkty jsou zobrazeny v pageable GridView

Obrázek 8: Produkty jsou zobrazeny v zobrazení Pageable GridView (kliknutím zobrazíte obrázek v plné velikosti)

Změna přiřazení kategorií má za následek porušení omezení cizího klíče.

Obrázek 9: Opětovné přiřazení kategorií způsobí porušení omezení cizího klíče (kliknutím zobrazíte obrázek v plné velikosti)

Teď v prohlížeči stiskněte tlačítko Zpět a klikněte na tlačítko Aktualizovat mřížku. Po aktualizaci dat by se měl zobrazit úplně stejný výstup jako na obrázku 8. To znamená, že i když byly některé produkty CategoryID změněny na právní hodnoty a aktualizovány v databázi, byly vráceny zpět, když došlo k porušení omezení cizího klíče.

Teď zkuste kliknout na tlačítko Upravit kategorie (BEZ TRANSAKCE). Výsledkem bude stejná chyba porušení omezení cizího klíče (viz obrázek 9), ale tentokrát se produkty, jejichž CategoryID hodnoty byly změněny na právní hodnotu, nevrátí zpět. Stiskněte tlačítko Zpět v prohlížeči a pak tlačítko Aktualizovat mřížku. Jak ukazuje obrázek 10, CategoryID došlo k opětovnému přiřazení s z prvních osmi produktů. Například na obrázku 8 měl CategoryID Chang hodnotu 1, ale na obrázku 10 byla znovu přiřazena k 2.

Některé hodnoty CategoryID produktů byly aktualizovány, zatímco jiné nebyly aktualizovány.

Obrázek 10: Hodnoty některých produktů CategoryID byly aktualizovány, zatímco jiné ne (kliknutím zobrazíte obrázek v plné velikosti)

Souhrn

Ve výchozím nastavení metody TableAdapter nezabalují provedené databázové příkazy v rámci rozsahu transakce, ale s trochou práce můžeme přidat metody, které vytvoří, potvrdí a vrátí zpět transakce. V tomto kurzu jsme ve ProductsTableAdapter třídě vytvořili tři takové metody: BeginTransaction, CommitTransactiona RollbackTransaction. Viděli jsme, jak pomocí těchto metod společně s blokem Try...Catch udělat řadu příkazů pro úpravy dat atomické. Konkrétně jsme vytvořili metodu UpdateWithTransaction v ProductsTableAdapter, která používá model Dávkové aktualizace k provedení nezbytných úprav řádků zadaného ProductsDataTableobjektu . Do třídy BLL jsme také přidali metodu DeleteProductsWithTransactionProductsBLL , která jako vstup přijímá ProductIDList hodnoty a volá metodu Delete DB-Direct vzor pro každý ProductIDobjekt . Obě metody začínají vytvořením transakce a poté spuštěním příkazů změny dat v rámci Try...Catch bloku. Pokud dojde k výjimce, transakce se vrátí zpět, jinak je potvrzena.

Krok 5 ilustroval účinek transakčních dávkových aktualizací oproti aktualizacím dávky, které transakci nepoužíly. V dalších třech kurzech budeme stavět na základech v tomto kurzu a vytvoříme uživatelská rozhraní pro dávkové aktualizace, odstraňování a vkládání.

Všechno nejlepší na programování!

Další čtení

Další informace o tématech probíraných v tomto kurzu najdete v následujících zdrojích informací:

O autorovi

Scott Mitchell, autor sedmi knih o ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, školitel a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Můžete ho zastihnout na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na adrese http://ScottOnWriting.NET.

Zvláštní poděkování

Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Hlavními recenzenty pro tento kurz byli Dave Gardner, Hilton Giesenow a Teresa Murphy. Chtěli byste si projít své nadcházející články na webu MSDN? Pokud ano, dejte mi řádek na mitchell@4GuysFromRolla.com.