Sdílet prostřednictvím


Zabalení úprav databáze do transakce (C#)

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íme, jak databázové transakce umožňují provádět dávkové úpravy jako atomické operace, což zajišťuje, že všechny kroky proběhnou úspěšně nebo všechny kroky selžou.

Úvod

Jak jsme viděli od kurzu Vložení, aktualizace a odstranění dat , poskytuje GridView integrovanou podporu úprav a odstraňování na úrovni řádků. S několika kliknutími myši je možné vytvořit bohaté rozhraní pro úpravy dat bez psaní řádku kódu, pokud jste obsah s úpravami a odstraňováním na jednotlivých řádcích. V některých scénářích je to ale nedostatečné a musíme uživatelům poskytnout možnost upravovat nebo odstraňovat dávku záznamů.

Například většina webových e-mailových klientů používá mřížku k výpisu každé zprávy, 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í dávkové úpravy je ideální v situacích, kdy uživatelé často upravují mnoho různých záznamů. Místo vynucení, aby uživatel klikl na Upravit, proveďte jeho změnu a potom klikněte na tlačítko Aktualizovat pro každý záznam, který je potřeba upravit, rozhraní dávkové úpravy vykreslí každý řádek s jeho rozhraním pro úpravy. Uživatel může rychle změnit sadu řádků, které je potřeba změnit, a pak tyto změny uložit kliknutím na tlačítko Aktualizovat vše. V této sadě kurzů se podívá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 dávkové odstranění rozhraní – co by se mělo stát, pokud 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á se první odstranění záznamu vrátit zpět, nebo je přijatelné, aby první záznam zůstal odstraněný?

Pokud chcete, aby dávková operace byla považována za atomické operace, jedna z nich, kde všechny kroky proběhly ú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í atomicitu pro sadu INSERT, UPDATEa DELETE příkazy spouštěné pod deštníkem 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 na použití databázových transakcí. V dalších kurzech se podíváme na implementaci webových stránek pro dávkové vkládání, aktualizace a odstraňování rozhraní. Pojďme začít!

Poznámka:

Při úpravě dat v dávkové transakci není atomita vždy nutná. V některých scénářích může být přijatelné mít některé úpravy dat ú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 zpracovávané 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é operace, kdy je atomicita důležitá. Když zákazník přesune finanční prostředky z jednoho bankovního účtu do jiného, musí se provést dvě operace: prostředky se musí odečíst z prvního účtu a pak se přidají do druhého. I když si banka nemusí myslet na úspěch prvního kroku, ale druhý krok selže, jeho zákazníci by rozuměli rozruchu. Doporučuji vám, abyste si prošli tento kurz a implementovali vylepšení DAL pro podporu databázových transakcí, i když 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é jednotky práce. Databázové příkazy, které tvoří transakci, jsou zaručeny atomické, což znamená, že 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 dojde k chybě v jednom z příkazů z kroku 2, vrácení transakce 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 zpět lze zadat ručně při psaní skriptů SQL nebo vytváření uložených procedur, nebo prostřednictvím programových prostředků 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 dalším kurzu se podíváme na to, jak používat uložené procedury ve vrstvě přístupu k datům, kdy prozkoumáme příkazy SQL pro vytváření, vracení zpět a potvrzení transakcí.

Poznámka:

Třída TransactionScope 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 Serveru, databáze Oracle a webová služba. Rozhodl jsem se použít ADO.NET transakce pro tento kurz místo TransactionScope třídy, 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 třída TransactionScope používá Microsoft Distributed Transaction Coordinator (MSDTC). Problémy s konfigurací, implementací a výkonem související s MSDTC jsou spíše specializované a pokročilé téma a nad rámec těchto kurzů.

Při práci s poskytovatelem SqlClient v ADO.NET jsou transakce inicializovány voláním SqlConnection metody třídy, BeginTransaction 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í přenese do catch bloku, kde transakce lze vrátit zpět prostřednictvím metody objektuSqlTransactionRollback. Pokud jsou všechny příkazy úspěšně dokončeny, volání metody objektuCommit SqlTransaction na konci try bloku potvrzení transakce. Tento vzor ilustruje následující fragment kódu. Viz Údržba konzistence databáze s transakcemi.

// 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;
}

Ve výchozím nastavení tableAdapter v Typed DataSet nepoužívají transakce. Abychom mohli poskytovat podporu transakcí, musíme rozšířit Třídy TableAdapter zahrnout další metody, které používají výše uvedený vzor k provedení řady příkazů úprav dat v rámci oboru transakce. V kroku 2 se dozvíte, jak tyto metody přidat pomocí částečných tříd.

Krok 1: Vytvoření práce s webovými stránkami dávkových dat

Než začneme zkoumat, jak rozšířit DAL na podporu databázových transakcí, pojďme nejprve chvíli vytvořit ASP.NET webových stránek, které budeme potřebovat pro tento kurz, a tři následující. Začněte přidáním nové složky s názvem BatchData a pak přidejte následující ASP.NET stránky a přidružte každou stránku ke stránce předlohy Site.master .

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

Přidání stránek ASP.NET pro kurzy související s SqlDataSource

Obrázek 1: Přidání ASP.NET stránek pro kurzy související s SqlDataSource

Stejně jako u ostatních složek Default.aspx se pomocí SectionLevelTutorialListing.ascx uživatelského ovládacího prvku zobrazí seznam kurzů v jeho části. Proto tento uživatelský ovládací prvek přidáte Default.aspx přetažením z Průzkumník řešení do návrhového zobrazení 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.sitemapsi chvíli prohlédněte web kurzů prostřednictvím prohlížeče. Nabídka vlevo teď obsahuje položky pro práci s kurzy dávkových dat.

Mapa webu teď obsahuje položky pro kurzy práce s dávkovými daty.

Obrázek 3: Mapa webu teď obsahuje položky pro práci se dávkovými datovými kurzy

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

Jak jsme si probrali v prvním kurzu, vytvoření vrstvy přístupu k datům se typová datová sada v naší DAL skládá z datových tabulek a objektů TableAdapter. DataTables uchovávají data, zatímco TableAdapter poskytují funkce pro čtení dat z databáze do DataTables, aktualizovat databázi změnami provedenými v tabulkách DataTables atd. Vzpomeňte si, že objekty TableAdapter poskytují dva vzory pro aktualizaci dat, které se označují jako Batch Update a DB-Direct. Se vzorem Dávkové aktualizace se objekt TableAdapter předá datové sadě, datové tabulce nebo kolekci objektů DataRows. Tato data se vyčtou a pro každý vložený, upravený nebo odstraněný řádek, příkaz InsertCommand, UpdateCommandnebo DeleteCommand se spustí. Při použití vzoru DB-Direct se objekt TableAdapter místo toho předává hodnoty sloupců nezbytných pro vložení, aktualizaci nebo odstranění jednoho záznamu. Metoda modelu Direct DB pak použije tyto předávané hodnoty ke spuštění příslušného InsertCommandpříkazu , UpdateCommandnebo DeleteCommand příkazu.

Bez ohledu na použitý vzor aktualizace metody 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 jedinou diskrétní 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 volal metodu TableAdapter s Insert desetkrát. Pokud prvních pět vložení proběhne úspěšně, ale šestý z nich způsobil výjimku, první pět vložených záznamů zůstane v databázi. Podobně platí, že pokud se vzor dávkové aktualizace používá k provádění vkládání, aktualizací a odstraňování vložených, upravených a odstraněných řádků v tabulce DataTable, pokud bylo prvních několik úprav úspěšné, ale později došlo k chybě, tyto dřívější změny, které se dokončily, zůstanou v databázi.

V určitých scénářích chceme zajistit atomicitu napříč řadou úprav. Abychom toho dosáhli, musíme ručně rozšířit TableAdapter přidáním nových metod, které spouští InsertCommand, UpdateCommanda DeleteCommand s pod deštníkem transakce. Při vytvář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 také použít s tableAdaptery.

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

Přidání složky s názvem TransactionSupport a souboru třídy s názvem ProductsTableAdapter.TransactionSupport.cs

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

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

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();
        }
   }
}

Klíčové partial slovo v deklaraci třídy zde označuje kompilátoru, že členy přidané uvnitř jsou přidány do ProductsTableAdapter třídy v NorthwindTableAdapters oboru názvů. using System.Data.SqlClient Všimněte si 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ání svých příkazů do databáze. V důsledku toho potřebujeme 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čeny publica umožňují jejich použití z , ProductsTableAdapterz jiné třídy v DAL nebo z jiné vrstvy architektury, jako je BLL. BeginTransaction otevře TableAdapter s interní SqlConnection (v případě potřeby), zahájí transakci a přiřadí ji k Transaction vlastnosti 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 objekty Commit a Rollback metody.

Krok 3: Přidání metod pro aktualizaci a odstranění dat pod deštníkem transakce

S těmito metodami jsme připraveni přidat metody do ProductsDataTable nebo BLL, které provádějí řadu příkazů pod deštníkem transakce. 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ů pro úpravu dat. Pokud volání metody objektu Adapter Update vede k výjimce, provádění se přenese do bloku, kde catch bude transakce vrácena zpět a výjimka znovu vyvolá. Vzpomeňte si, že metoda implementuje model Batch Update tím, že Update vyčíslí řádky zadaného ProductsDataTable a provede nezbytné 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 je potvrzena v plném rozsahu.

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

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

Metoda UpdateWithTransaction používá model Batch Update, ale řadu volání DB-Direct lze použít také v rámci rozsahu transakce, jak ukazuje následující metoda. Metoda DeleteProductsWithTransaction přijímá jako vstup List<T> typu int, což jsou ProductID s k odstranění. Metoda inicializuje transakci prostřednictvím volání BeginTransaction a pak v try bloku iteruje prostřednictvím zadaného seznamu volání DB-Direct Delete metody pro každou ProductID hodnotu. Pokud některá z volání Delete se nezdaří, řízení se přenese do catch bloku, ve kterém je transakce vrácena zpět a výjimka znovu vyvolána. Pokud jsou všechna volání Delete úspěšná, transakce je potvrzena. Přidejte tuto metodu ProductsBLL do třídy.

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

Použití transakcí napříč několika objektů TableAdapter

Kód související s transakcemi, který jsme prozkoumali v tomto kurzu, umožňuje, aby se několik příkazů vůči ProductsTableAdapter ní považovalo za atomické operace. Ale co když je potřeba provést několik úprav různých databázových tabulek atomicky? Když například odstraníme kategorii, můžeme napřed chtít znovu přiřadit své aktuální produkty k některé jiné kategorii. Tyto dva kroky znovu přiřaďte produkty a odstraňte kategorii jako atomické operace. ProductsTableAdapter Ale zahrnuje 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 CategoriesTableAdapter pojmenované DeleteCategoryAndReassignProducts(categoryIDtoDelete, reassignToCategoryID) a mít tuto metodu volání uložené procedury, která znovu přiřazuje produkty a odstraní kategorii v rámci transakce definované v rámci uložené procedury. V dalším kurzu se podíváme na to, jak začít, potvrdit a vrátit transakce zpět 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 by vytvořila instanci CategoriesTableAdapter a ProductsTableAdapter pak tyto dvě Vlastnosti TableAdapter Connection na stejnou SqlConnection instanci. V tomto okamžiku by jeden ze dvou TableAdapter inicioval transakci s 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 potvrzenou transakcí nebo vrácen zpět podle potřeby.

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

V kroku 3 jsme do dal přidali UpdateWithTransaction metodu ProductsTableAdapter . Do BLL bychom měli přidat odpovídající metodu. Zatímco prezentační vrstva by mohla zavolat přímo do DAL vyvolat metodu UpdateWithTransaction , tyto kurzy se snažily definovat vrstvenou architekturu, která izoluje DAL z prezentační vrstvy. Proto nás to vychytá, abychom pokračovali 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. Nyní by měly existovat dvě nové metody: ProductsBLLUpdateWithTransaction, které jste právě přidali, a DeleteProductsWithTransaction, které byly přidány v kroku 3.

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

Poznámka:

Tyto metody nezahrnují DataObjectMethodAttribute atribut přiřazený většině dalších metod třídy ProductsBLL , protože tyto metody budeme vyvolávat přímo z ASP.NET stránek třídy kódu za sebou. Vzpomeňte si, že DataObjectMethodAttribute slouží k označení metod, které by se měly zobrazit v Průvodci konfigurací zdroje dat ObjectDataSource a na jaké kartě (SELECT, UPDATE, INSERT nebo DELETE). Vzhledem k tomu, že GridView nemá žádnou integrovanou podporu dávkové úpravy nebo odstranění, budeme muset tyto metody vyvolat programově, a nebudeme používat deklarativní přístup bez kódu.

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

Abychom ilustrovali efekt, který má 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 Web tlačítka, který při kliknutí znovu přiřazuje hodnoty produktů CategoryID . Konkrétně se změní přiřazení kategorie tak, aby bylo přiřazování prvních několika produktů přiřazeno platné CategoryID hodnoty, zatímco jiné mají účelově přiřazenou neexistující CategoryID hodnotu. Pokud se pokusíme aktualizovat databázi produktem, jehož 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 vyvolaná výjimka z porušení omezení cizího klíče způsobí vrácení předchozích platných CategoryID změn zpět. Pokud však nepoužíváte transakci, změny počátečních kategorií zůstanou.

Začněte otevřením Transactions.aspx stránky ve BatchData složce a přetažením objektu GridView ze sady nástrojů do Návrháře. Nastavte jeho ID hodnotu Products a z inteligentní značky vytvořte vazbu na nový ObjectDataSource s názvem ProductsDataSource. Nakonfigurujte ObjectDataSource tak, aby načítá data z ProductsBLL metody třídy s GetProducts . Jedná se o 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.

Obrázek 5: Konfigurace ObjectDataSource pro použití metody GetProducts třídy ProductsBLL

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

Nastavte rozevírací seznamy na kartách UPDATE, INSERT a DELETE na (Žádné).

Obrázek 6: Nastavení rozevíracích seznamů 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 visual Studio vytvoří BoundFields a CheckBoxField pro pole dat produktu. Odeberte všechna tato pole s výjimkou ProductID, ProductNameCategoryID, a CategoryName přejmenujte ProductName CategoryName vlastnosti a BoundFields HeaderText na Product a Category( v uvedeném pořadí). Na inteligentní značce zaškrtněte možnost Povolit stránkování. Po provedení těchto úprav by deklarativní kód 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 vlastnost Text prvního tlačítka na Aktualizovat mřížku, druhý s upravit kategorie (WITH TRANSACTION) a třetí s upravit kategorie (BEZ TRANSAKCE) .

<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 mělo zobrazení návrhu v sadě Visual Studio vypadat podobně jako na snímku obrazovky zobrazeném 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 a Click použijte následující kód:

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();
}

Obslužná rutina události refresh Button s Click jednoduše znovubinuje data do GridView voláním Products GridView s DataBind metoda.

Druhá obslužná rutina události znovu přiřazuje produkty CategoryID a používá novou metodu transakce z BLL k provádění aktualizací databáze pod deštníkem transakce. Všimněte si, že každý produkt s CategoryID je libovolně nastaven na stejnou hodnotu jako její ProductID. To bude fungovat u prvních několika produktů, protože tyto produkty mají ProductID hodnoty, které se namapují na platné CategoryID hodnoty. Ale jakmile ProductID začne být příliš velký, tento shodný překrytí ProductID s a CategoryID 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. Tato Update metoda nezabaluje řadu příkazů v rámci transakce, takže tyto změny jsou provedeny před prvním zjištěným porušením omezení cizího klíče bude zachována chyba.

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. Dále klikněte na tlačítko Upravit kategorie (WITH TRANSACTION). 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 se zobrazují v objektu GridView s možností stránky.

Obrázek 8: Produkty se zobrazují v objektu GridView s možností stránky (kliknutím zobrazíte obrázek v plné velikosti).

Změna přiřazení kategorií způsobí porušení omezení cizího klíče.

Obrázek 9: Opětovné přiřazení výsledků kategorií v porušení omezení cizího klíče (kliknutím zobrazíte obrázek s plnou velikostí)

Teď stiskněte tlačítko Zpět v prohlížeči a potom 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ž se některé produkty CategoryID změnily na právní hodnoty a aktualizovaly se 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 Změnit kategorie (BEZ TRANSAKCE). Výsledkem bude stejná chyba porušení omezení cizího klíče (viz obrázek 9), ale tentokrát se tyto produkty, jejichž CategoryID hodnoty byly změněny na právní hodnotu, nebudou vráceny zpět. Stiskněte tlačítko Zpět v prohlížeči a pak na tlačítko Aktualizovat mřížku. Jak ukazuje obrázek 10, CategoryID došlo k opětovnému přiřazení prvních osmi produktů. Například na obrázku 8 měla Chang hodnotu CategoryID 1, ale na obrázku 10 byla znovu přiřazena 2.

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

Obrázek 10: Některé hodnoty produktů CategoryID byly aktualizovány, zatímco jiné nebyly (kliknutím zobrazíte obrázek plné velikosti)

Shrnutí

Ve výchozím nastavení metody TableAdapter s nezabalují provedené databázové příkazy v rámci oboru transakce, ale s trochou práce můžeme přidat metody, které vytvoří, potvrzení a vrácení transakce zpět. V tomto kurzu jsme vytvořili tři takové metody ve ProductsTableAdapter třídě: BeginTransaction, CommitTransactiona RollbackTransaction. Viděli jsme, jak tyto metody používat spolu s blokem try...catch k vytvoření řady příkazů pro úpravy dat atomické. Konkrétně jsme vytvořili metodu UpdateWithTransaction v ProductsTableAdapter, která používá model Batch Update k provedení nezbytných úprav řádků zadaného ProductsDataTable. Přidali jsme také metodu DeleteProductsWithTransaction ProductsBLL do třídy VLL, která přijímá List hodnoty ProductID jako vstup a volá metodu Delete vzoru DB-Direct pro každý ProductID. Obě metody začínají vytvořením transakce a následným spuštěním příkazů pro úpravu dat v try...catch rámci bloku. Pokud dojde k výjimce, transakce se vrátí zpět, jinak se potvrdí.

Krok 5 znázorňuje účinek transakčních dávkových aktualizací a dávkových aktualizací, které zanedbály použití transakce. V dalších třech kurzech stavíme na základech uvedených v tomto kurzu a vytvoříme uživatelská rozhraní pro provádění dávkových aktualizací, odstraňování a vkládání.

Šťastné 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 ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, trenér a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 za 24 hodin. Je dostupný na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím svého blogu, který lze najít na http://ScottOnWriting.NET.

Zvláštní díky

Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Vedoucí recenzenti tohoto kurzu byli Dave Gardner, Hilton Giesenow a Teresa Murphy. Chcete si projít nadcházející články MSDN? Pokud ano, zahoďte mi řádek na mitchell@4GuysFromRolla.com.