Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V předchozích kurzech jsme vytvořili příkazy SQL v kódu a předali příkazy do databáze, která se má spustit. Alternativním přístupem je použití uložených procedur, kdy jsou příkazy SQL předdefinované v databázi. V tomto kurzu se naučíme, jak může průvodce TableAdapter pro nás generovat nové uložené procedury.
Úvod
Vrstva přístupu k datům (DAL) pro tyto kurzy používá typy datových sad. Jak je popsáno v kurzu Vytvoření vrstvy přístupu k datům , typové datové sady se skládají z datových tabulek a objektů TableAdapter se silnými typy. Tabulky DataTables představují logické entity v systému, zatímco TableAdapters interagují s podkladovou databází pro provádění přístupu k datům. To zahrnuje naplnění datových tabulek dat daty, spouštění dotazů, které vracejí skalární data, a vkládání, aktualizaci a odstraňování záznamů z databáze.
Příkazy SQL spouštěné sadou TableAdapters můžou být ad hoc příkazy SQL, jako je SELECT columnList FROM TableName
, nebo uložené procedury. TableAdaptery v naší architektuře používají ad hoc příkazy SQL. Mnoho vývojářů a správců databází ale upřednostňuje uložené procedury před ad hoc příkazy SQL z důvodů zabezpečení, udržovatelnosti a aktualizovatelnosti. Jiní dávají přednost ad hoc příkazům SQL pro jejich flexibilitu. Ve své vlastní práci dávám přednost uloženým procedurám před ad hoc příkazy SQL, ale rozhodl jsem se použít ad hoc příkazy SQL ke zjednodušení předchozích kurzů.
Když definujete Objekt TableAdapter nebo přidáváte nové metody, průvodce TableAdapter s usnadňuje vytváření nových uložených procedur nebo použití existujících uložených procedur, stejně jako při použití příkazů SQL ad hoc. V tomto tutoriálu se podíváme, jak průvodce TableAdapter automaticky vygeneruje uložené procedury. V dalším kurzu se podíváme na to, jak nakonfigurovat metody TableAdapter s tak, aby používaly existující nebo ručně vytvořené uložené procedury.
Poznámka:
Podívejte se na blogový příspěvek Roba Howarda Don t Use Stored Procedures Yet? a blogový příspěvek Franse BoumyStored Procedures are Bad, M Kay? pro živou debatu o výhodách a nevýhodách uložených procedur a ad-hoc SQL.
Základy uložených procedur
Funkce jsou konstruktorem, který je společný pro všechny programovací jazyky. Funkce je kolekce příkazů, které se spouští při zavolání funkce. Funkce můžou přijímat vstupní parametry a volitelně vracet hodnotu.
Uložené procedury jsou databázové konstrukce, které sdílejí mnoho podobností s funkcemi v programovacích jazycích. Uložená procedura se skládá ze sady příkazů T-SQL, které se spouští při volání uložené procedury. Uložená procedura může přijímat nula až mnoho vstupních parametrů a může vracet skalární hodnoty, výstupní parametry nebo nejčastěji sady výsledků z dotazů SELECT
.
Poznámka:
Uložené procedury jsou často označovány jako „sprocs“ nebo „SPs“.
Uložené procedury se vytvářejí pomocí CREATE PROCEDURE
příkazu T-SQL. Například následující skript T-SQL vytvoří uloženou proceduru s názvem GetProductsByCategoryID
, která přijímá jeden parametr s názvem @CategoryID
a vrátí pole ProductID
, ProductName
, UnitPrice
a Discontinued
z těchto sloupců v tabulce Products
, které mají odpovídající hodnotu CategoryID
.
CREATE PROCEDURE GetProductsByCategoryID
(
@CategoryID int
)
AS
SELECT ProductID, ProductName, UnitPrice, Discontinued
FROM Products
WHERE CategoryID = @CategoryID
Po vytvoření této uložené procedury ji můžete volat pomocí následující syntaxe:
EXEC GetProductsByCategory categoryID
Poznámka:
V dalším kurzu prozkoumáme vytváření uložených procedur prostřednictvím integrovaného vývojového prostředí sady Visual Studio. V tomto kurzu ale necháme průvodce TableAdapter automaticky generovat uložené procedury pro nás.
Kromě pouhého vrácení dat se uložené procedury často používají k provádění více databázových příkazů v rámci jedné transakce. Uložená procedura s názvem DeleteCategory
, například, může vzít parametr @CategoryID
a provést dva DELETE
příkazy: první, jeden odstranit související produkty a druhý odstranit zadanou kategorii. Více příkazů v rámci uložené procedury nejsou automaticky zabaleny v rámci transakce. Další příkazy T-SQL je potřeba vydat, aby se zajistilo, že více příkazů v uložené proceduře je považováno za jednu atomickou operaci. V následujícím kurzu se naučíme, jak zahrnout příkazy uložené procedury do transakce.
Při použití uložených procedur v architektuře metody vrstvy přístupu k datům vyvolávají konkrétní uloženou proceduru místo vydání příkazu AD hoc SQL. Tím se centralizuje umístění příkazů SQL spuštěných (v databázi) místo toho, aby bylo definováno v architektuře aplikace. Tato centralizace pravděpodobně usnadňuje hledání, analýzu a ladění dotazů a poskytuje mnohem jasnější obrázek o tom, kde a jak se databáze používá.
Další informace o základech uložených procedur najdete v části Dodatečné informace na konci tohoto tutoriálu.
Krok 1: Vytvoření scénáře webových stránek.
Než začneme s diskuzí o vytváření DAL pomocí uložených procedur, věnujme nejprve chvíli vytvoření ASP.NET stránek v našem webovém projektu, které budeme potřebovat pro tento a několik dalších výukových programů. Začněte přidáním nové složky s názvem AdvancedDAL
. Dále do této složky přidejte následující ASP.NET stránky a nezapomeňte přidružit každou stránku ke stránce předlohy Site.master
:
Default.aspx
NewSprocs.aspx
ExistingSprocs.aspx
JOINs.aspx
AddingColumns.aspx
ComputedColumns.aspx
EncryptingConfigSections.aspx
ManagedFunctionsAndSprocs.aspx
Obrázek 1: Přidat stránky ASP.NET pro scénáře pokročilé vrstvy přístupu k datům do tutoriálů
Stejně jako v ostatních složkách Default.aspx
se ve AdvancedDAL
složce zobrazí seznam kurzů v jeho části. Vzpomeňte si, že SectionLevelTutorialListing.ascx
uživatelské řízení tuto funkci poskytuje. Tento uživatelský ovládací prvek přidejte do Default.aspx
přetažením z Průzkumníka řešení do návrhového zobrazení 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 stránky jako položky do Web.sitemap
souboru. Konkrétně přidejte následující značení po práci s dávkovými daty <siteMapNode>
:
<siteMapNode url="~/AdvancedDAL/Default.aspx"
title="Advanced DAL Scenarios"
description="Explore a number of advanced Data Access Layer scenarios.">
<siteMapNode url="~/AdvancedDAL/NewSprocs.aspx"
title="Creating New Stored Procedures for TableAdapters"
description="Learn how to have the TableAdapter wizard automatically
create and use stored procedures." />
<siteMapNode url="~/AdvancedDAL/ExistingSprocs.aspx"
title="Using Existing Stored Procedures for TableAdapters"
description="See how to plug existing stored procedures into a
TableAdapter." />
<siteMapNode url="~/AdvancedDAL/JOINs.aspx"
title="Returning Data Using JOINs"
description="Learn how to augment your DataTables to work with data
returned from multiple tables via a JOIN query." />
<siteMapNode url="~/AdvancedDAL/AddingColumns.aspx"
title="Adding DataColumns to a DataTable"
description="Master adding new columns to an existing DataTable." />
<siteMapNode url="~/AdvancedDAL/ComputedColumns.aspx"
title="Working with Computed Columns"
description="Explore how to work with computed columns when using
Typed DataSets." />
<siteMapNode url="~/AdvancedDAL/EncryptingConfigSections.aspx"
title="Protected Connection Strings in Web.config"
description="Protect your connection string information in
Web.config using encryption." />
<siteMapNode url="~/AdvancedDAL/ManagedFunctionsAndSprocs.aspx"
title="Creating Managed SQL Functions and Stored Procedures"
description="See how to create SQL functions and stored procedures
using managed code." />
</siteMapNode>
Po aktualizaci Web.sitemap
si chvíli prohlédněte web kurzů prostřednictvím prohlížeče. Nabídka vlevo teď obsahuje položky pro pokročilé kurzy scénářů DAL.
Obrázek 3: Mapa webu teď obsahuje položky pro kurzy pokročilých scénářů DAL
Krok 2: Konfigurace prvku TableAdapter pro vytvoření nových uložených procedur
Abychom si ukázali vytvoření vrstvy přístupu k datům, která místo ad hoc příkazů SQL používá uložené procedury, vytvoříme ve složce pojmenovanou NorthwindWithSprocs.xsd
novou typovou datovou sadu~/App_Code/DAL
. Vzhledem k tomu, že jsme tento proces podrobně prošli v předchozích kurzech, budeme rychle procházet zde uvedené kroky. Pokud se zablokujete nebo potřebujete další podrobné pokyny k vytvoření a konfiguraci typové datové sady, projděte si kurz Vytvoření vrstvy přístupu k datům .
Přidejte do projektu novou datovou sadu tak, že kliknete pravým tlačítkem myši na DAL
složku, zvolíte Přidat novou položku a vyberete šablonu Datové sady, jak je znázorněno na obrázku 4.
Obrázek 4: Přidání nové typové datové sady do projektu s názvem NorthwindWithSprocs.xsd
(kliknutím zobrazíte obrázek s plnou velikostí)
Tím vytvoříte novou typovou datovou sadu, otevřete její návrháře, vytvoříte nový TableAdapter a spustíte průvodce konfigurací TableAdapter. Průvodce konfigurací TableAdapter s prvním krokem nás požádá, abychom vybrali databázi, se kterými chcete pracovat. Připojovací řetězec k databázi Northwind by měl být uvedený v rozevíracím seznamu. Vyberte tuto možnost a klikněte na Další.
Na této další obrazovce můžeme zvolit, jak má Objekt TableAdapter přistupovat k databázi. V předchozích kurzech jsme vybrali první možnost– Použít příkazy SQL. Pro účely tohoto kurzu vyberte druhou možnost, Vytvořte nové uložené procedury a klikněte na Další.
Obrázek 5: Pokyn k vytvoření nových uložených procedur v sadě TableAdapter (kliknutím zobrazíte obrázek s plnou velikostí)
Stejně jako při použití ad hoc příkazů SQL se v následujícím kroku zobrazí výzva k zadání SELECT
příkazu pro hlavní dotaz TableAdapter. Místo použití SELECT
příkazu, který zde zadáte k přímému provedení ad hoc dotazu, průvodce TableAdapter s vytvoří uloženou proceduru, která obsahuje tento SELECT
dotaz.
Pro tento parametr TableAdapter použijte následující SELECT
dotaz:
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued
FROM Products
Obrázek 6: Zadejte SELECT
dotaz (kliknutím zobrazíte obrázek s plnou velikostí)
Poznámka:
Výše uvedený dotaz se mírně liší od hlavního ProductsTableAdapter
dotazu v Northwind
typové datové sadě. Vzpomeňte si, že ProductsTableAdapter
v Northwind
zadané datové sadě jsou dvě korelované poddotazy, které vrátí název kategorie a název společnosti pro každou kategorii a dodavatele produktů. V nadcházejícím tutoriálu o aktualizaci TableAdapteru na použití JOINů se podíváme na přidání těchto souvisejících dat do tohoto TableAdapteru.
Chvíli klikněte na tlačítko Upřesnit možnosti. Odsud můžeme určit, jestli má průvodce také generovat příkazy insert, update a delete pro TableAdapter, zda použít optimistickou souběžnost a zda by se měla tabulka dat aktualizovat po vložení a aktualizacích. Ve výchozím nastavení je zaškrtnuto políčko Generovat příkazy Insert, Update a Delete. Nechte ho zaškrtnuté. Pro tento návod nechte možnosti Použít optimistickou souběžnost nezaškrtnuté.
Při automatickém vytvoření uložených procedur průvodcem TableAdapter se zobrazí, že je možnost Aktualizovat tabulku dat ignorována. Bez ohledu na to, jestli je toto políčko zaškrtnuté, výsledné vložené a aktualizované procedury načtou právě vložený nebo právě aktualizovaný záznam, jak uvidíme v kroku 3.
Obrázek 7: Ponechte zaškrtnutou možnost vygenerovat příkazy Vložit, Aktualizovat a Odstranit
Poznámka:
Pokud je zaškrtnuto políčko Použít optimistickou souběžnost, průvodce přidá do WHERE
klauzule další podmínky, které brání aktualizaci dat, pokud došlo ke změnám v jiných polích. Další informace o použití integrované funkce řízení optimistické souběžnosti TableAdapteru najdete v tutoriálu Implementace optimistické souběžnosti.
Po zadání dotazu a potvrzení, že je zaškrtnuto SELECT
políčko Generovat příkazy Vložit, Aktualizovat a Odstranit, klepněte na tlačítko Další. Tato další obrazovka zobrazená na obrázku 8 zobrazí výzvu k zadání názvů uložených procedur, které průvodce vytvoří pro výběr, vložení, aktualizaci a odstranění dat. Změňte názvy uložených procedur na Products_Select
, Products_Insert
, Products_Update
a Products_Delete
.
Obrázek 8: Přejmenování uložených procedur (kliknutím zobrazíte obrázek s plnou velikostí)
Chcete-li zobrazit T-SQL, který průvodce TableAdapter použije k vytvoření čtyř uložených procedur, klikněte na tlačítko Náhled skriptu SQL. V dialogovém okně Náhled skriptu SQL můžete skript uložit do souboru nebo ho zkopírovat do schránky.
Obrázek 9: Náhled skriptu SQL použitého k vygenerování uložených procedur
Po pojmenování uložených procedur klepněte na tlačítko Další, abyste pojmenovali metody odpovídajícího objektu TableAdapter. Stejně jako při použití ad hoc příkazů SQL můžeme vytvořit metody, které vyplní existující tabulku DataTable nebo vrátí novou. Můžeme také určit, jestli má model TableAdapter obsahovat DB-Direct vzor pro vkládání, aktualizaci a odstraňování záznamů. Nechejte zaškrtnutá všechna tři políčka, ale přejmenujte metodu Return a DataTable na GetProducts
(jak je znázorněno na obrázku 10).
Obrázek 10: Pojmenování metod Fill
a GetProducts
(kliknutím zobrazíte obrázek s plnou velikostí)
Kliknutím na tlačítko Další zobrazíte souhrn kroků, které průvodce provede. Dokončete průvodce kliknutím na tlačítko Dokončit. Po dokončení průvodce se vrátíte do Návrháře sady dat, která by teď měla obsahovat ProductsDataTable
.
Obrázek 11: Návrhář datové sady zobrazuje nově přidaný ProductsDataTable
obrázek (kliknutím zobrazíte obrázek s plnou velikostí).
Krok 3: Zkoumání nově vytvořených uložených procedur
Průvodce TableAdapter použitý v kroku 2 automaticky vytvořil uložené procedury pro výběr, vkládání, aktualizaci a odstraňování dat. Tyto uložené procedury je možné zobrazit nebo upravit v sadě Visual Studio tak, že přejdete do Průzkumníka serveru a přejdete do složky Uložené procedury databáze. Jak ukazuje obrázek 12, databáze Northwind obsahuje čtyři nové uložené procedury: Products_Delete
, Products_Insert
, Products_Select
a Products_Update
.
Obrázek 12: Čtyři uložené procedury vytvořené v kroku 2 najdete ve složce Uložené procedury databáze.
Poznámka:
Pokud průzkumníka serveru nevidíte, přejděte do nabídky Zobrazení a zvolte možnost Průzkumník serveru. Pokud nevidíte uložené procedury související s produktem přidané z kroku 2, zkuste kliknout pravým tlačítkem myši na složku Uložené procedury a zvolit Aktualizovat.
Pokud chcete zobrazit nebo upravit uloženou proceduru, poklikejte na jeho název v Průzkumníku serveru nebo případně klikněte pravým tlačítkem myši na uloženou proceduru a zvolte Otevřít. Obrázek 13 znázorňuje uloženou proceduru Products_Delete
, když je otevřená.
Obrázek 13: Uložené procedury je možné otevřít a upravit v sadě Visual Studio (kliknutím zobrazíte obrázek s plnou velikostí).
Obsah uložených Products_Delete
Products_Select
procedur je poměrně jednoduchý. Uložené procedury Products_Insert
a Products_Update
naproti tomu vyžadují bližší kontrolu, protože obě provádějí SELECT
příkaz po svých INSERT
a UPDATE
příkazech. Například následující SQL tvoří uloženou proceduru Products_Insert
:
ALTER PROCEDURE dbo.Products_Insert
(
@ProductName nvarchar(40),
@SupplierID int,
@CategoryID int,
@QuantityPerUnit nvarchar(20),
@UnitPrice money,
@UnitsInStock smallint,
@UnitsOnOrder smallint,
@ReorderLevel smallint,
@Discontinued bit
)
AS
SET NOCOUNT OFF;
INSERT INTO [Products] ([ProductName], [SupplierID], [CategoryID], [QuantityPerUnit],
[UnitPrice], [UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued])
VALUES (@ProductName, @SupplierID, @CategoryID, @QuantityPerUnit, @UnitPrice,
@UnitsInStock, @UnitsOnOrder, @ReorderLevel, @Discontinued);
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice,
UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued
FROM Products
WHERE (ProductID = SCOPE_IDENTITY())
Uložená procedura přijímá jako vstupní parametry Products
sloupce vrácené dotazem SELECT
zadaným v průvodci TableAdapter s a tyto hodnoty se používají v INSERT
příkazu. Po příkazu INSERT
se dotaz SELECT
použije k vrácení Products
hodnot sloupců (včetně ProductID
) nově přidaného záznamu. Tato funkce aktualizace je užitečná při přidávání nového záznamu pomocí vzoru Dávkové aktualizace, protože automaticky aktualizuje nově přidané ProductRow
vlastnosti instancí ProductID
s automaticky navyšovanými hodnotami přiřazenými databází.
Tuto funkci ilustruje následující kód. Obsahuje ProductsTableAdapter
a ProductsDataTable
vytvořený pro typovou datovou sadu NorthwindWithSprocs
. Do databáze se přidá nový produkt vytvořením ProductsRow
instance, zadáním jeho hodnot a voláním Metody TableAdapter s Update
předáním ProductsDataTable
. Interně metoda TableAdapter s Update
vyčísluje ProductsRow
instance v předané DataTable (v tomto příkladu existuje pouze jeden - ten, který jsme právě přidali) a provede příslušný příkaz insert, update nebo delete. V tomto případě Products_Insert
se spustí uložená procedura, která do tabulky přidá nový záznam Products
a vrátí podrobnosti nově přidaného záznamu. Hodnota ProductsRow
instance ProductID
se pak aktualizuje. Po dokončení metody Update
můžeme prostřednictvím vlastnosti ProductsRow
ProductID
získat přístup k hodnotě nově přidaného záznamu ProductID
.
' Create the ProductsTableAdapter and ProductsDataTable
Dim productsAPI As New NorthwindWithSprocsTableAdapters.ProductsTableAdapter
Dim products As New NorthwindWithSprocs.ProductsDataTable
' Create a new ProductsRow instance and set its properties
Dim product As NorthwindWithSprocs.ProductsRow = products.NewProductsRow()
product.ProductName = "New Product"
product.CategoryID = 1 ' Beverages
product.Discontinued = False
' Add the ProductsRow instance to the DataTable
products.AddProductsRow(product)
' Update the DataTable using the Batch Update pattern
productsAPI.Update(products)
' At this point, we can determine the value of the newly-added record's ProductID
Dim newlyAddedProductIDValue as Integer = product.ProductID
Uložená procedura Products_Update
obsahuje podobně SELECT
příkaz za UPDATE
příkazem.
ALTER PROCEDURE dbo.Products_Update
(
@ProductName nvarchar(40),
@SupplierID int,
@CategoryID int,
@QuantityPerUnit nvarchar(20),
@UnitPrice money,
@UnitsInStock smallint,
@UnitsOnOrder smallint,
@ReorderLevel smallint,
@Discontinued bit,
@Original_ProductID int,
@ProductID int
)
AS
SET NOCOUNT OFF;
UPDATE [Products]
SET [ProductName] = @ProductName, [SupplierID] = @SupplierID,
[CategoryID] = @CategoryID, [QuantityPerUnit] = @QuantityPerUnit,
[UnitPrice] = @UnitPrice, [UnitsInStock] = @UnitsInStock,
[UnitsOnOrder] = @UnitsOnOrder, [ReorderLevel] = @ReorderLevel,
[Discontinued] = @Discontinued
WHERE (([ProductID] = @Original_ProductID));
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit,
UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued
FROM Products
WHERE (ProductID = @ProductID)
Všimněte si, že tato uložená procedura obsahuje dva vstupní parametry pro ProductID
: @Original_ProductID
a @ProductID
. Tato funkce umožňuje scénáře, ve kterých se může změnit primární klíč. Například v databázi zaměstnanců může každý záznam zaměstnance jako primární klíč použít číslo sociálního pojištění zaměstnance. Aby bylo možné změnit číslo sociálního pojištění stávajícího zaměstnance, musí být zadáno nové číslo sociálního pojištění i původní.
Products
U tabulky není taková funkce nutná, protože ProductID
sloupec je IDENTITY
sloupec a nikdy by se neměl měnit. Ve skutečnosti UPDATE
příkaz v uložené proceduře Products_Update
neobsahuje sloupec ProductID
ve svém seznamu sloupců.
@Original_ProductID
Zatímco se tedy používá v klauzuli s WHERE
příkazu UPDATE
, je nadbytečný pro tabulku Products
a může být nahrazen parametrem @ProductID
. Při úpravě parametrů uložených procedur je důležité aktualizovat také metody TableAdapter, které používají uloženou proceduru.
Krok 4: Úprava parametrů uložených procedur a aktualizace objektu TableAdapter
Vzhledem k tomu, že @Original_ProductID
je parametr nadbytečný, pojďme ho Products_Update
úplně odebrat z uložené procedury. Otevřete uloženou proceduru Products_Update
@Original_ProductID
, odstraňte parametr a v WHERE
klauzuli UPDATE
příkazu změňte název parametru použitý z @Original_ProductID
na @ProductID
. Po provedení těchto změn by T-SQL v rámci uložené procedury měl vypadat takto:
ALTER PROCEDURE dbo.Products_Update
(
@ProductName nvarchar(40),
@SupplierID int,
@CategoryID int,
@QuantityPerUnit nvarchar(20),
@UnitPrice money,
@UnitsInStock smallint,
@UnitsOnOrder smallint,
@ReorderLevel smallint,
@Discontinued bit,
@ProductID int
)
AS
SET NOCOUNT OFF;
UPDATE [Products] SET [ProductName] = @ProductName, [SupplierID] = @SupplierID,
[CategoryID] = @CategoryID, [QuantityPerUnit] = @QuantityPerUnit,
[UnitPrice] = @UnitPrice, [UnitsInStock] = @UnitsInStock,
[UnitsOnOrder] = @UnitsOnOrder, [ReorderLevel] = @ReorderLevel,
[Discontinued] = @Discontinued
WHERE (([ProductID] = @ProductID));
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit,
UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued
FROM Products
WHERE (ProductID = @ProductID)
Pokud chcete tyto změny uložit do databáze, klikněte na ikonu Uložit na panelu nástrojů nebo stiskněte Ctrl+S. V tomto okamžiku Products_Update
uložená procedura neočekává @Original_ProductID
vstupní parametr, ale TableAdapter je nakonfigurován tak, aby předal takový parametr. Parametry, které TableAdapter odešle do Products_Update
uložené procedury, můžete zobrazit tak, že v Návrháři datové sady vyberete TableAdapter, přejdete do okna Vlastnosti a kliknete na tlačítko s třemi tečkami v kolekci UpdateCommand
s Parameters
. Zobrazí se dialogové okno Editor kolekcí parametrů zobrazené na obrázku 14.
Obrázek 14: Editor kolekce parametrů uvádí parametry, které se předají uložené proceduře Products_Update
Tento parametr odsud můžete odebrat jednoduše tak @Original_ProductID
, že vyberete parametr ze seznamu členů a kliknete na tlačítko Odebrat.
Případně můžete aktualizovat parametry použité pro všechny metody tak, že v Návrháři kliknete pravým tlačítkem myši na TableAdapter a zvolíte Konfigurovat. Tím se zobrazí průvodce konfigurací TableAdapter, který obsahuje uložené procedury používané k výběru, vkládání, aktualizaci a odstraňování, spolu s parametry, které uložené procedury očekávají. Pokud kliknete na rozevírací seznam Aktualizovat, uvidíte očekávané vstupní parametry uložených procedur Products_Update
, které již nezahrnují @Original_ProductID
(viz obrázek 15). Kliknutím na tlačítko Dokončit automaticky aktualizujte kolekci parametrů používanou objektem TableAdapter.
Obrázek 15: Případně můžete pomocí Průvodce konfigurací TableAdapter aktualizovat kolekce parametrů metod (kliknutím zobrazíte obrázek v plné velikosti).
Krok 5: Přidání dalších metod TableAdapter
Jak je znázorněno v kroku 2, při vytváření nového objektu TableAdapter je snadné mít odpovídající uložené procedury automaticky vygenerovány. Totéž platí při přidávání dalších metod do objektu TableAdapter. Abychom to mohli ilustrovat, pojďme přidat metodu do vytvořeného GetProductByProductID(productID)
ProductsTableAdapter
v kroku 2. Tato metoda převezme jako vstup ProductID
hodnotu a vrátí podrobnosti o zadaném produktu.
Začněte tak, že kliknete pravým tlačítkem na objekt TableAdapter a v místní nabídce zvolíte Přidat dotaz.
Obrázek 16: Přidání nového dotazu do prvku TableAdapter
Tím se spustí Průvodce konfigurací dotazu TableAdapter, který nejprve vyzve, jak má TableAdapter přistupovat k databázi. Chcete-li vytvořit novou uloženou proceduru, zvolte možnost Vytvořit novou uloženou proceduru a klepněte na tlačítko Další.
Obrázek 17: Volba možnosti Vytvořit novou uloženou proceduru (Kliknutím zobrazíte obrázek s plnou velikostí)
Na další obrazovce je třeba identifikovat typ dotazu, který se má provést, ať už vrátí sadu řádků nebo jednu skalární hodnotu, nebo provede příkaz UPDATE
, INSERT
nebo DELETE
. Vzhledem k tomu, že metoda GetProductByProductID(productID)
vrátí řádek, ponechte možnost SELEKT, která vrací řádek, vybranou a stiskněte Další.
Obrázek 18: Zvolte výběr, který vrací možnost řádku (kliknutím zobrazíte obrázek s plnou velikostí)
Na další obrazovce se zobrazí hlavní dotaz TableAdapter, který zobrazí jenom název uložené procedury (dbo.Products_Select
). Nahraďte název uložené procedury následujícím SELECT
příkazem, který vrátí všechna pole produktu pro zadaný produkt:
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued
FROM Products
WHERE ProductID = @ProductID
Obrázek 19: Nahrazení názvu uložené procedury dotazem SELECT
(kliknutím zobrazíte obrázek s plnou velikostí)
Na následující obrazovce se zobrazí dotaz, jestli chcete pojmenovat uloženou proceduru, která se vytvoří. Zadejte název Products_SelectByProductID
a klikněte na Další.
Obrázek 20: Pojmenování nové uložené procedury Products_SelectByProductID
(kliknutím zobrazíte obrázek v plné velikosti)
Poslední krok průvodce nám umožňuje změnit názvy vygenerovaných metod a také indikovat, jestli se má použít vzor Fill a DataTable, Return a DataTable nebo obojí. Pro tuto metodu ponechte obě možnosti zaškrtnuté, ale přejmenujte metody na FillByProductID
a GetProductByProductID
. Kliknutím na tlačítko Další zobrazíte souhrn kroků, které průvodce provede, a potom kliknutím na tlačítko Dokončit průvodce dokončete.
Obrázek 21: Přejmenování metod TableAdapter s na FillByProductID
a GetProductByProductID
(kliknutím zobrazíte obrázek s plnou velikostí)
Po dokončení průvodce má TableAdapter k dispozici novou metodu, GetProductByProductID(productID)
která při vyvolání spustí uloženou Products_SelectByProductID
proceduru, která byla právě vytvořena. Chvíli si prohlédněte tuto novou uloženou proceduru z Průzkumníka serveru tak, že přejdete do složky Uložené procedury a otevřete Products_SelectByProductID
ji (pokud ji nevidíte, klikněte pravým tlačítkem myši na složku Uložené procedury a zvolte Aktualizovat).
Všimněte si, že uložená SelectByProductID
procedura přebírá @ProductID
jako vstupní parametr a spouští SELECT
příkaz, který jsme zadali v průvodci.
ALTER PROCEDURE dbo.Products_SelectByProductID
(
@ProductID int
)
AS
SET NOCOUNT ON;
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued
FROM Products
WHERE ProductID = @ProductID
Krok 6: Vytvoření třídy vrstvy obchodní logiky
V rámci série kurzů jsme se snažili zachovat vrstvenou architekturu, ve které prezentační vrstva provedla všechna svá volání do vrstvy obchodní logiky (BLL). Abychom mohli toto rozhodnutí o návrhu dodržovat, musíme nejprve vytvořit třídu BLL pro novou typovou datovou sadu, než budeme mít přístup k datům produktu z prezentační vrstvy.
Ve složce ~/App_Code/BLL
vytvořte nový soubor třídy ProductsBLLWithSprocs.vb
a přidejte do něj následující kód:
Imports NorthwindWithSprocsTableAdapters
<System.ComponentModel.DataObject()> _
Public Class ProductsBLLWithSprocs
Private _productsAdapter As ProductsTableAdapter = Nothing
Protected ReadOnly Property Adapter() As ProductsTableAdapter
Get
If _productsAdapter Is Nothing Then
_productsAdapter = New ProductsTableAdapter()
End If
Return _productsAdapter
End Get
End Property
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Select, True)> _
Public Function GetProducts() As NorthwindWithSprocs.ProductsDataTable
Return Adapter.GetProducts()
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductByProductID(ByVal productID As Integer) _
As NorthwindWithSprocs.ProductsDataTable
Return Adapter.GetProductByProductID(productID)
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Insert, True)> _
Public Function AddProduct _
(ByVal productName As String, ByVal supplierID As Nullable(Of Integer), _
ByVal categoryID As Nullable(Of Integer), ByVal quantityPerUnit As String, _
ByVal unitPrice As Nullable(Of Decimal), _
ByVal unitsInStock As Nullable(Of Short), _
ByVal unitsOnOrder As Nullable(Of Short), _
ByVal reorderLevel As Nullable(Of Short), _
ByVal discontinued As Boolean) _
As Boolean
' Create a new ProductRow instance
Dim products As New NorthwindWithSprocs.ProductsDataTable()
Dim product As NorthwindWithSprocs.ProductsRow = products.NewProductsRow()
product.ProductName = productName
If Not supplierID.HasValue Then
product.SetSupplierIDNull()
Else
product.SupplierID = supplierID.Value
End If
If Not categoryID.HasValue Then
product.SetCategoryIDNull()
Else
product.CategoryID = categoryID.Value
End If
If quantityPerUnit Is Nothing Then
product.SetQuantityPerUnitNull()
Else
product.QuantityPerUnit = quantityPerUnit
End If
If Not unitPrice.HasValue Then
product.SetUnitPriceNull()
Else
product.UnitPrice = unitPrice.Value
End If
If Not unitsInStock.HasValue Then
product.SetUnitsInStockNull()
Else
product.UnitsInStock = unitsInStock.Value
End If
If Not unitsOnOrder.HasValue Then
product.SetUnitsOnOrderNull()
Else
product.UnitsOnOrder = unitsOnOrder.Value
End If
If Not reorderLevel.HasValue Then
product.SetReorderLevelNull()
Else
product.ReorderLevel = reorderLevel.Value
End If
product.Discontinued = discontinued
' Add the new product
products.AddProductsRow(product)
Dim rowsAffected As Integer = Adapter.Update(products)
' Return true if precisely one row was inserted, otherwise false
Return rowsAffected = 1
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateProduct
(ByVal productName As String, ByVal supplierID As Nullable(Of Integer), _
ByVal categoryID As Nullable(Of Integer), ByVal quantityPerUnit As String, _
ByVal unitPrice As Nullable(Of Decimal), _
ByVal unitsInStock As Nullable(Of Short), _
ByVal unitsOnOrder As Nullable(Of Short), _
ByVal reorderLevel As Nullable(Of Short), _
ByVal discontinued As Boolean, ByVal productID As Integer) _
As Boolean
Dim products As NorthwindWithSprocs.ProductsDataTable = _
Adapter.GetProductByProductID(productID)
If products.Count = 0 Then
' no matching record found, return false
Return False
End If
Dim product As NorthwindWithSprocs.ProductsRow = products(0)
product.ProductName = productName
If Not supplierID.HasValue Then
product.SetSupplierIDNull()
Else
product.SupplierID = supplierID.Value
End If
If Not categoryID.HasValue Then
product.SetCategoryIDNull()
Else
product.CategoryID = categoryID.Value
End If
If quantityPerUnit Is Nothing Then
product.SetQuantityPerUnitNull()
Else
product.QuantityPerUnit = quantityPerUnit
End If
If Not unitPrice.HasValue Then
product.SetUnitPriceNull()
Else
product.UnitPrice = unitPrice.Value
End If
If Not unitsInStock.HasValue Then
product.SetUnitsInStockNull()
Else
product.UnitsInStock = unitsInStock.Value
End If
If Not unitsOnOrder.HasValue Then
product.SetUnitsOnOrderNull()
Else
product.UnitsOnOrder = unitsOnOrder.Value
End If
If Not reorderLevel.HasValue Then
product.SetReorderLevelNull()
Else
product.ReorderLevel = reorderLevel.Value
End If
product.Discontinued = discontinued
' Update the product record
Dim rowsAffected As Integer = Adapter.Update(product)
' Return true if precisely one row was updated, otherwise false
Return rowsAffected = 1
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Delete, True)> _
Public Function DeleteProduct(ByVal productID As Integer) As Boolean
Dim rowsAffected As Integer = Adapter.Delete(productID)
' Return true if precisely one row was deleted, otherwise false
Return rowsAffected = 1
End Function
End Class
Tato třída napodobuje sémantiku třídy z předchozích kurzů, ale používá objekty ProductsTableAdapter
a ProductsDataTable
z NorthwindWithSprocs
DataSet. Například, místo toho, aby byl příkaz na začátku souboru třídy, jako je tomu u Imports NorthwindTableAdapters
, třída ProductsBLLWithSprocs
používá Imports NorthwindWithSprocsTableAdapters
. Podobně jsou objekty ProductsDataTable
a ProductsRow
použité v této třídě označeny předponou NorthwindWithSprocs
oboru názvů. Třída ProductsBLLWithSprocs
poskytuje dvě metody přístupu k datům GetProducts
a GetProductByProductID
a metody pro přidání, aktualizaci a odstranění jedné instance produktu.
Krok 7: Práce s datovouNorthwindWithSprocs
sadou z prezentační vrstvy
V tuto chvíli jsme vytvořili DAL, který používá uložené procedury pro přístup k podkladovým datům databáze a jejich úpravu. Také jsme vytvořili základní BLL s metodami pro načtení všech produktů nebo konkrétního produktu spolu s metodami pro přidávání, aktualizaci a odstraňování produktů. Abychom tento kurz zaokrouhlili, vytvoříme ASP.NET stránku, která používá třídu BLL s ProductsBLLWithSprocs
k zobrazení, aktualizaci a odstraňování záznamů.
Otevřete stránku ve AdvancedDAL
složce a přetáhněte GridView z panelu nástrojů do návrháře a přiřadíme ji název Products
. Z inteligentní značky GridView zvolte vytvořit vazbu na nový ObjectDataSource s názvem ProductsDataSource
. Nakonfigurujte ObjectDataSource tak, aby používal ProductsBLLWithSprocs
třídu, jak je znázorněno na obrázku 22.
Obrázek 22: Konfigurace ObjectDataSource pro použití ProductsBLLWithSprocs
třídy (kliknutím zobrazíte obrázek s plnou velikostí)
Rozevírací seznam na kartě SELECT má dvě možnosti GetProducts
a GetProductByProductID
. Vzhledem k tomu, že chceme zobrazit všechny produkty v GridView, zvolte metodu GetProducts
. Rozevírací seznamy na kartách UPDATE, INSERT a DELETE mají pouze jednu metodu. Ujistěte se, že každý z těchto rozevíracích seznamů má vybranou příslušnou metodu, a klikněte na tlačítko Dokončit.
Po dokončení průvodce ObjectDataSource Visual Studio přidá BoundFields a CheckBoxField do GridView pro datová pole produktů. Zapněte integrovanou úpravu a odstraňování funkcí GridView tak, že zaškrtnete možnosti Povolit úpravy a Povolit odstranění, které jsou přítomné na inteligentní značce.
Obrázek 23: Stránka obsahuje objekt GridView s povolenou podporou úprav a odstraňování (kliknutím zobrazíte obrázek v plné velikosti).
Jak jsme probrali v předchozích kurzech, při dokončení průvodce pro ObjectDataSource Visual Studio nastaví vlastnost OldValuesParameterFormatString
na původní hodnotu original_{0}. To je potřeba vrátit k výchozí hodnotě {0} , aby funkce úprav dat fungovaly správně vzhledem k parametrům očekávaným metodami v naší BLL. Proto nezapomeňte nastavit vlastnost OldValuesParameterFormatString
na {0} nebo zcela odebrat vlastnost z deklarativní syntaxe.
Po dokončení Průvodce konfigurací zdroje dat, zapnutí podpory úprav a odstranění v GridView a vrácení vlastnosti ObjectDataSource OldValuesParameterFormatString
na výchozí hodnotu by deklarativní značka vaší stránky měla vypadat podobně jako následující:
<asp:GridView ID="Products" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsDataSource">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="ProductID" HeaderText="ProductID"
InsertVisible="False" ReadOnly="True"
SortExpression="ProductID" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName"
SortExpression="ProductName" />
<asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
SortExpression="SupplierID" />
<asp:BoundField DataField="CategoryID" HeaderText="CategoryID"
SortExpression="CategoryID" />
<asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit"
SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock"
SortExpression="UnitsInStock" />
<asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder"
SortExpression="UnitsOnOrder" />
<asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel"
SortExpression="ReorderLevel" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
DeleteMethod="DeleteProduct" InsertMethod="AddProduct"
SelectMethod="GetProducts" TypeName="ProductsBLLWithSprocs"
UpdateMethod="UpdateProduct">
<DeleteParameters>
<asp:Parameter Name="productID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="supplierID" Type="Int32" />
<asp:Parameter Name="categoryID" Type="Int32" />
<asp:Parameter Name="quantityPerUnit" Type="String" />
<asp:Parameter Name="unitPrice" Type="Decimal" />
<asp:Parameter Name="unitsInStock" Type="Int16" />
<asp:Parameter Name="unitsOnOrder" Type="Int16" />
<asp:Parameter Name="reorderLevel" Type="Int16" />
<asp:Parameter Name="discontinued" Type="Boolean" />
<asp:Parameter Name="productID" Type="Int32" />
</UpdateParameters>
<InsertParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="supplierID" Type="Int32" />
<asp:Parameter Name="categoryID" Type="Int32" />
<asp:Parameter Name="quantityPerUnit" Type="String" />
<asp:Parameter Name="unitPrice" Type="Decimal" />
<asp:Parameter Name="unitsInStock" Type="Int16" />
<asp:Parameter Name="unitsOnOrder" Type="Int16" />
<asp:Parameter Name="reorderLevel" Type="Int16" />
<asp:Parameter Name="discontinued" Type="Boolean" />
</InsertParameters>
</asp:ObjectDataSource>
V tuto chvíli bychom mohli GridView upravit přizpůsobením rozhraní pro úpravy tak, aby zahrnovalo ověření, přičemž sloupce CategoryID
a SupplierID
by se vykreslovaly jako rozbalovací seznamy atd. Můžeme také přidat potvrzení na straně klienta na tlačítko Odstranit, a doporučuji vám, abyste si vzali čas na implementaci těchto vylepšení. Vzhledem k tomu, že tato témata jsou popsána v předchozích kurzech, nebudeme je zde znovu pokrývat.
Bez ohledu na to, jestli gridview vylepšíte nebo ne, otestujte základní funkce stránky v prohlížeči. Jak je znázorněno na obrázku 24, stránka obsahuje seznam produktů v objektu GridView, který poskytuje možnosti úprav a odstraňování jednotlivých řádků.
Obrázek 24: Produkty lze zobrazit, upravit a odstranit z Objektu GridView (kliknutím zobrazíte obrázek v plné velikosti).
Shrnutí
Objekty TableAdapter v typové datové sadě mají přístup k datům z databáze pomocí příkazů SQL ad hoc nebo prostřednictvím uložených procedur. Při práci s uloženými procedurami je možné použít existující uložené procedury nebo průvodce TableAdapter lze instruovat k vytvoření nových uložených procedur na SELECT
základě dotazu. V tomto kurzu jsme prozkoumali, jak pro nás uložené procedury automaticky vytvořit.
Zatímco automatické generování uložených procedur pomáhá ušetřit čas, existují určité případy, kdy uložená procedura vytvořená průvodcem neodpovídá tomu, co bychom vytvořili sami. Jedním z příkladů je uložená Products_Update
procedura, která očekávala oba @Original_ProductID
i @ProductID
vstupní parametry, i když @Original_ProductID
byl parametr nadbytečný.
V mnoha scénářích už můžou být uložené procedury vytvořené nebo je můžeme chtít sestavit ručně, aby měly lepší kontrolu nad příkazy uložených procedur. V obou případech bychom chtěli dát objektu TableAdapter pokyn, aby pro své metody používal existující uložené procedury. V dalším kurzu se dozvíme, jak toho dosáhnout.
Šť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 Naučte se sami ASP.NET 2.0 během 24 hodin. Může být dosažitelný na mitchell@4GuysFromRolla.comadrese .
Zvláštní díky
Tato série kurzů byla zkontrolována mnoha užitečnými recenzenty. Vedoucím recenzentem pro tento tutoriál byl Hilton Geisenow. Chcete si projít nadcházející články MSDN? Pokud ano, napište mi zprávu na mitchell@4GuysFromRolla.com.