Zabalení úprav databáze do transakce (C#)
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 úprav a odstraňování na úrovni řádků. Pomocí několika kliknutí myši je možné vytvořit bohaté rozhraní pro úpravu dat bez zápisu řádku kódu, pokud jste spokojení s úpravami a odstraňováním po 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 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-mailech (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. Dávkové rozhraní pro úpravy je ideální v situacích, kdy uživatelé často upravují mnoho různých záznamů. Místo toho, aby uživatel nutí kliknout na Upravit, provést změnu a potom kliknout na Aktualizovat pro každý záznam, který je třeba upravit, vykreslí rozhraní dávkové úpravy každý řádek s jeho rozhraním pro úpravy. Uživatel může rychle upravit 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 mělo být možné, aby některé operace v dávce byly úspěšné, zatímco jiné selžou. Zvažte dávkové odstranění rozhraní – co by se mělo stát, když se první vybraný záznam úspěšně odstraní, ale druhý selže, například kvůli porušení omezení cizího klíče? Má být odstraněn první záznam vrácen 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, kdy buď 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í atomicitu pro sadu INSERT
příkazů , UPDATE
a 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í, aktualizace a odstraňování rozhraní. Pojďme začít!
Poznámka
Při úpravě dat v dávkové transakci není vždy nutná atomicita. V některých scénářích může být přijatelné, aby některé úpravy dat proběhly ú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 nemusí být dal upravován, aby podporoval databázové transakce. Existují ale i jiné scénáře dávkových operací, ve kterých je atomicita zásadní. Když zákazník přesune své prostředky z jednoho bankovního účtu na jiný, musí se provést dvě operace: finanční prostředky musí být odečteny z prvního účtu a pak přidány k druhému. I když bance nemusí vadit, že první krok uspěje, ale druhý krok selže, její zákazníci by byli pochopitelně naštvaná. Doporučuji vám, abyste tento kurz propracovali 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é 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:
- Označuje začátek transakce.
- Spusťte příkazy SQL, které tvoří transakci.
- Pokud v jednom z příkazů z kroku 2 dojde k chybě, vraťte transakci zpět.
- Pokud se všechny příkazy z kroku 2 dokončí bez chyby, potvrďte transakci.
Příkazy SQL použité 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 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. V tomto okamžiku prozkoumáme příkazy SQL pro vytváření, vrácení zpět a potvrzení transakcí.
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 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 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 zahájeny voláním SqlConnection
metody třídy sBeginTransaction
, která vrací SqlTransaction
objekt. Příkazy úprav 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. Tento vzor znázorňuje 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í TableAdaptery v typed DataSet nepoužívají transakce. Abychom mohli poskytovat podporu transakcí, musíme rozšířit třídy TableAdapter o další metody, které používají výše uvedený vzor k provedení řady příkazů úprav dat v rámci rozsahu transakce. V kroku 2 se dozvíte, jak tyto metody přidat pomocí částečných tříd.
Krok 1: Vytvoření webové stránky s daty v dávkách
Než začneme zkoumat, jak rozšířit DAL o podporu databázových transakcí, udělejte 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í. 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, 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
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 výpisu kurzů ve své části. Proto přidejte tento uživatelský ovládací prvek do Default.aspx
tak, že ho přetáhnete z Průzkumník řešení do zobrazení Návrh stránky.
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.sitemap
si chvíli prohlédněte web kurzů v prohlížeči. Nabídka na levé straně 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 dávkovými daty.
Krok 2: Aktualizace vrstvy přístupu k datům na podporu databázových transakcí
Jak jsme probrali v prvním kurzu Vytvoření vrstvy přístupu k datům, typed DataSet v dal se skládá z DataTables a TableAdapter. Tabulky DataTables uchovávají data, zatímco funkce TableAdapter poskytují funkce pro čtení dat z databáze do tabulek DataTables, aktualizaci databáze změnami provedenými v tabulkách DataTables atd. Vzpomeňte si, že objekty TableAdapter poskytují dva vzory pro aktualizaci dat, které jsem označil jako Batch Update a DB-Direct. Se vzorem Batch Update 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 InsertCommand
se spustí , UpdateCommand
nebo DeleteCommand
. Se vzorem DB-Direct se do pole TableAdapter místo toho předávají hodnoty sloupců potřebných pro vložení, aktualizaci nebo odstranění jednoho záznamu. Metoda modelu DB Direct pak tyto předané hodnoty použije ke spuštění příslušného InsertCommand
příkazu , UpdateCommand
nebo DeleteCommand
.
Bez ohledu na použitý vzor aktualizace automaticky generované metody TableAdapter 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 vedlo k výjimce, prvních pět vložených záznamů zůstane v databázi. Podobně platí, že pokud se vzor dávkové aktualizace používá k vkládání, aktualizacím a odstraňování řádků vložených, upravených a odstraněných řádků v tabulce DataTable, pokud se prvních několik úprav úspěšně provedlo, ale později došlo k chybě, zůstanou tyto dřívější úpravy, které byly dokončeny, v databázi.
V některých scénářích chceme zajistit atomicitu napříč řadou úprav. Abychom toho dosáhli, musíme ručně rozšířit Objekt TableAdapter přidáním nových metod, které provádějí InsertCommand
, UpdateCommand
a DeleteCommand
s 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 zadané datové sadě. Tuto techniku lze použít také s sadou TableAdapter.
Typed DataSet Northwind.xsd
se nachází v podsložce App_Code
složky s DAL
. Vytvořte ve DAL
složce podsložku 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 pro provádění úprav dat pomocí transakce.
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é v rámci mají být přidány do ProductsTableAdapter
třídy v NorthwindTableAdapters
oboru názvů. Všimněte si using 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é , public
což 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
. CommitTransaction
a 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
, UpdateCommand
a 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 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
. 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 ProductsBLL
ProductsTableAdapter
).this.RollbackTransaction()
this.CommitTransaction()
this.BeginTransaction()
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<T>
typ int
, 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 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í 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é CategoriesTableAdapter
DeleteCategoryAndReassignProducts(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íUpdateWithTransaction
metody 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 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ě 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.
Obrázek 5: Obrázek 5: Konfigurace objektu ObjectDataSource pro použití ProductsBLL
metody Třídy s GetProducts
(kliknutím zobrazíte obrázek v plné velikosti)
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
, ProductName
CategoryID
, a CategoryName
přejmenujte ProductName
vlastnosti BoundFields HeaderText
CategoryName
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.
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 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 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).
Obrázek 8: Produkty jsou zobrazeny v zobrazení Pageable GridView (kliknutím zobrazíte obrázek v plné velikosti)
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.
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 s nezabalují spuštěné databázové příkazy do rozsahu transakce, ale s trochou práce můžeme přidat metody, které vytvoří, potvrdí a vrátí zpět transakci. V tomto kurzu jsme ve ProductsTableAdapter
třídě vytvořili tři takové metody: BeginTransaction
, CommitTransaction
a RollbackTransaction
. Viděli jsme, jak pomocí těchto metod společně s blokem try...catch
vytvořit řadu příkazů pro úpravy dat atomické. Konkrétně jsme vytvořili metodu UpdateWithTransaction
v objektu ProductsTableAdapter
, který používá model Batch Update k provedení nezbytných úprav řádků zadaného ProductsDataTable
objektu . Také jsme přidali metodu DeleteProductsWithTransaction
do ProductsBLL
třídy v BLL, která přijímá ProductID
List
hodnoty jako svůj vstup a volá DB-Direct vzor metodu Delete
pro každý ProductID
objekt . Obě metody začínají vytvořením transakce a poté spuštěním příkazů úprav dat v rámci try...catch
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í oproti aktualizacím dávky, které zanedbály použití transakce. V dalších třech kurzech budeme stavět na základech 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í:
- Snadné transakce:
System.Transactions
- TransactionScope a DataAdaptery
- Použití oracle database transactions v .NET
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 najít na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na http://ScottOnWriting.NETadrese .
Zvláštní poděkování
Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Hlavními recenzenty tohoto kurzu byli Dave Gardner, Hilton Giesenow a Teresa Murphy. Chcete si projít moje nadcházející články na WEBU MSDN? Pokud ano, dejte mi čáru na mitchell@4GuysFromRolla.comadresu .
Váš názor
https://aka.ms/ContentUserFeedback.
Připravujeme: V průběhu roku 2024 budeme postupně vyřazovat problémy z GitHub coby mechanismus zpětné vazby pro obsah a nahrazovat ho novým systémem zpětné vazby. Další informace naleznete v tématu:Odeslat a zobrazit názory pro