Sdílet prostřednictvím


Vytvoření nových uložených procedur prvků TableAdapter typových sad dat (VB)

Scott Mitchell

Stáhnout PDF

V předchozích kurzech jsme v našem kódu vytvořili příkazy SQL a předali příkazy do databáze, která se má spustit. Alternativním přístupem je použití uložených procedur, kde jsou příkazy SQL předdefinované v databázi. V tomto kurzu se dozvíte, jak pro nás Průvodce objektem TableAdapter vygenerovat nové uložené procedury.

Úvod

Vrstva přístupu k datům (DAL) pro tyto kurzy používá typové datové sady. Jak je popsáno v kurzu Vytvoření vrstvy přístupu k datům , typové datové sady se skládají z datových tabulek se silnými typy a objektů TableAdapter. DataTables představují logické entity v systému, zatímco Objekty TableAdapter jsou v rozhraní s podkladovou databází, aby prováděly práci s přístupem k datům. To zahrnuje naplnění tabulek DataTables daty, spouštění dotazů, které vrací skalární data, a vkládání, aktualizaci a odstraňování záznamů z databáze.

Příkazy SQL spouštěné pomocí objektů TableAdapter můžou být buď příkazy SQL ad hoc, jako SELECT columnList FROM TableNameje , 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 kvůli zabezpečení, údržbě a aktualizovatelnosti dává přednost uloženým procedurám před ad hoc příkazy SQL. Jiní vřele preferují ad hoc příkazy SQL kvůli své flexibilitě. 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, aby se zjednodušily dřívější kurzy.

Při definování objektu TableAdapter nebo přidávání nových metod průvodce TableAdapter s usnadňuje vytváření nových uložených procedur nebo používání existujících uložených procedur stejně jako použití ad hoc příkazů SQL. V tomto kurzu se podíváme, jak automaticky vygenerovat uložené procedury pomocí průvodce TableAdapter. V dalším kurzu se podíváme na to, jak nakonfigurovat metody TableAdapter pro použití existujících nebo ručně vytvořených uložených procedur.

Poznámka

Podívejte se na blogovou položku Roba Howarda Nepoužívejte uložené procedury ještě? a franse Bouma s blogovou položkou Uložené procedury jsou špatné, M Kay? pro živou debatu o výhodách a nevýhodách uložených procedur a ad hoc SQL.

Základní informace o uložených procedurách

Funkce jsou konstruktor 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ě můžou vrátit 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 spustí 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 SELECT dotazů.

Poznámka

Uložené procedury se často označují 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ázvemGetProductsByCategoryID, která přijme jeden parametr s názvem @CategoryID a vrátí ProductIDpole , ProductNameUnitPrice, a Discontinued z těchto sloupců v Products tabulce, které mají odpovídající CategoryID hodnotu:

CREATE PROCEDURE GetProductsByCategoryID
(
    @CategoryID int
)
AS
SELECT ProductID, ProductName, UnitPrice, Discontinued
FROM Products
WHERE CategoryID = @CategoryID

Po vytvoření této uložené procedury je možné ji 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. Pro účely tohoto kurzu však necháme průvodce TableAdapter automaticky vygenerovat uložené procedury.

Kromě jednoduché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 DeleteCategorymůže například přijmout @CategoryID parametr a provést dva DELETE příkazy: první pro odstranění souvisejících produktů a druhý odstraňují zadanou kategorii. Více příkazů v rámci uložené procedury není automaticky zabaleno do transakce. Je potřeba vydat další příkazy T-SQL, aby se zajistilo, že se s více příkazy uložené procedury bude zacházet jako s atomické operace. V následujícím kurzu se dozvíme, jak zabalit příkazy uložené procedury do rozsahu transakce.

Při použití uložených procedur v rámci architektury metody data Access Layer místo vystavení příkazu SQL ad hoc vyvolají konkrétní uloženou proceduru. Tím se centralizuje umístění spuštěných příkazů SQL (v databázi) a nedefinuje se v rámci architektury aplikace. Tato centralizace pravděpodobně usnadňuje hledání, analýzu a ladění dotazů a poskytuje mnohem jasnější představu o tom, kde a jak se databáze používá.

Další informace o základech uložených procedur najdete v části Další informace na konci tohoto kurzu.

Krok 1: Vytvoření webových stránek Advanced Data Access Layer Scenarios

Než začneme diskutovat o vytvoření DAL pomocí uložených procedur, pojďme nejprve chvíli vytvořit ASP.NET stránky v našem webovém projektu, které budeme potřebovat pro tento a několik dalších kurzů. 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 Site.master stránce předlohy:

  • Default.aspx
  • NewSprocs.aspx
  • ExistingSprocs.aspx
  • JOINs.aspx
  • AddingColumns.aspx
  • ComputedColumns.aspx
  • EncryptingConfigSections.aspx
  • ManagedFunctionsAndSprocs.aspx

Přidání stránek ASP.NET pro kurzy scénářů pokročilého přístupu k datům

Obrázek 1: Přidání stránek ASP.NET pro scénáře pokročilého přístupu k datům

Stejně jako v ostatních složkách Default.aspx bude ve AdvancedDAL složce seznam kurzů ve své části. Vzpomeňte si SectionLevelTutorialListing.ascx , že tuto funkci poskytuje uživatelský ovládací prvek. 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.

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 stránky jako položky do Web.sitemap souboru. Konkrétně za položku Práce s daty <siteMapNode>v dávce přidejte následující kód:

<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.sitemapsi chvíli prohlédněte web kurzů v prohlížeči. Nabídka na levé straně teď obsahuje položky pro kurzy pokročilých scénářů DAL.

Mapa webu teď obsahuje položky pro kurzy pokročilých scénářů DAL.

Obrázek 3: Mapa webu teď obsahuje položky pro kurzy pokročilých scénářů DAL

Krok 2: Konfigurace nástroje TableAdapter pro vytvoření nových uložených procedur

Chcete-li si předvést vytvoření vrstvy přístupu k datům, která místo příkazů SQL ad hoc používá uložené procedury, vytvořte novou typovou sadu dat ve ~/App_Code/DAL složce s názvem NorthwindWithSprocs.xsd. Vzhledem k tomu, že jsme tento proces podrobně probrali v předchozích kurzech, budeme rychle pokračovat v těchto krocích. Pokud se zaseknete nebo potřebujete další podrobné pokyny k vytvoření a konfiguraci typové sady dat, 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 na DAL složku, zvolíte Přidat novou položku a vyberete šablonu DataSet, jak je znázorněno na obrázku 4.

Přidání nové datové sady s názvem NorthwindWithSprocs.xsd do projektu

Obrázek 4: Přidání nové zadané datové sady do projektu s názvem NorthwindWithSprocs.xsd (kliknutím zobrazíte obrázek v plné velikosti)

Tím se vytvoří nová sada Typed DataSet, otevře se její Designer, vytvoří se nový objekt TableAdapter a spustí se Průvodce konfigurací objektu TableAdapter. První krok Průvodce konfigurací nástroje TableAdapter nás vyzve, abychom vybrali databázi, se kterým chcete pracovat. V rozevíracím seznamu by měly být uvedené připojovací řetězec k databázi Northwind. Vyberte tuto možnost a klikněte na Další.

Na této další obrazovce můžeme zvolit, jak má TableAdapter přistupovat k databázi. V předchozích kurzech jsme vybrali první možnost Použití příkazů SQL. Pro účely tohoto kurzu vyberte druhou možnost Vytvořit nové uložené procedury a klikněte na Další.

Dát sadě TableAdapter pokyn k vytvoření nových uložených procedur

Obrázek 5: Řekněte sadě TableAdapter, aby vytvořil nové uložené procedury (kliknutím zobrazíte obrázek v plné velikosti)

Stejně jako u použití ad hoc příkazů SQL jsme v následujícím kroku požádáni o zadání SELECT příkazu pro hlavní dotaz TableAdapter s. Ale místo použití zde zadaného SELECT příkazu k provedení ad hoc dotazu přímo, průvodce TableAdapter s vytvoří uloženou proceduru, která obsahuje tento SELECT dotaz.

Pro tento tableAdapter použijte následující SELECT dotaz:

SELECT ProductID, ProductName, SupplierID, CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued
FROM Products

Zadejte dotaz SELECT.

Obrázek 6: Zadejte SELECT dotaz (kliknutím zobrazíte obrázek v plné velikosti)

Poznámka

Výše uvedený dotaz se mírně liší od hlavního ProductsTableAdapter dotazu v Northwind zadané datové sadě. Vzpomeňte si, že ProductsTableAdapter sada Northwind Typed DataSet obsahuje dva korelované poddotazy, které vrátí název kategorie a název společnosti pro každou kategorii produktu a dodavatele. V nadcházejícím kurzu Aktualizace objektu TableAdapter na použití sítí JOINs se podíváme na přidání těchto souvisejících dat do tohoto objektu TableAdapter.

Chvíli klikněte na tlačítko Upřesnit možnosti. Tady můžeme určit, jestli má průvodce také generovat příkazy insert, update a delete pro Objekt TableAdapter, jestli se má použít optimistická souběžnost a jestli se má po vložení a aktualizacích aktualizovat tabulka dat. Možnost Generovat příkazy Insert, Update a Delete je ve výchozím nastavení zaškrtnutá. Nechte ho zaškrtnuté. Pro účely tohoto kurzu ponechte možnost Použít optimistickou souběžnost nezaškrtnutou.

Při automatickém vytvoření uložených procedur průvodcem objektem TableAdapter se zdá, že možnost Aktualizovat tabulku dat je ignorována. Bez ohledu na to, jestli je toto políčko zaškrtnuté, výsledné uložené procedury vložení a aktualizace načtou právě vložený nebo aktualizovaný záznam, jak uvidíme v kroku 3.

Možnost Generovat příkazy Insert, Update a Delete nechte zaškrtnutou.

Obrázek 7: Nechte zaškrtnutou možnost Generovat příkazy Insert, Update a Delete.

Poznámka

Pokud je zaškrtnuté políčko Použít optimistickou souběžnost, průvodce přidá do WHERE klauzule další podmínky, které brání aktualizaci dat v případě změn v jiných polích. Další informace o používání integrované funkce řízení optimistické souběžnosti najdete v kurzu Implementace optimistické souběžnosti .

Po zadání SELECT dotazu a potvrzení, že je zaškrtnutá možnost Generovat příkazy Insert, Update a Delete, klikněte na Další. Na další obrazovce na obrázku 8 se zobrazí výzva 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 tyto názvy uložených procedur na Products_Select, Products_Insert, Products_Updatea Products_Delete.

Přejmenování uložených procedur

Obrázek 8: Přejmenování uložených procedur (kliknutím zobrazíte obrázek v plné velikosti)

Pokud chcete 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.

Náhled skriptu SQL použitého k vygenerování uložených procedur

Obrázek 9: Náhled skriptu SQL použitého ke generování uložených procedur

Po pojmenování uložených procedur klikněte na Další a pojmenujte odpovídající metody 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á tableAdapter obsahovat DB-Direct vzor pro vkládání, aktualizaci a odstraňování záznamů. Nechte 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).

Pojmenujte metody Fill a GetProducts.

Obrázek 10: Pojmenujte metody Fill a GetProducts (kliknutím zobrazíte obrázek v plné velikosti)

Kliknutím na 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 Designer datové sady, která by teď měla obsahovat ProductsDataTable.

The DataSet s Designer Shows the Newly Added ProductsDataTable

Obrázek 11: DataSet s Designer Zobrazuje nově přidaný ProductsDataTableobrázek (kliknutím zobrazíte obrázek v plné velikosti).

Krok 3: Prozkoumání nově vytvořených uložených procedur

Průvodce objektu TableAdapter použitý v kroku 2 automaticky vytvořil uložené procedury pro výběr, vložení, aktualizaci a odstranění dat. Tyto uložené procedury můžete zobrazit nebo upravit v sadě Visual Studio tak, že přejdete do Průzkumníka serveru a přejdete k podrobnostem 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_Selecta Products_Update.

Čtyři uložené procedury vytvořené v kroku 2 najdete ve složce Uložené procedury databáze.

Obrázek 12: Čtyři uložené procedury vytvořené v kroku 2 najdete ve složce Uložených procedur databáze.

Poznámka

Pokud se Průzkumník serveru nezobrazuje, 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é v kroku 2, zkuste kliknout pravým tlačítkem na složku Uložené procedury a zvolit Aktualizovat.

Chcete-li zobrazit nebo upravit uloženou proceduru, poklikejte na její název v Průzkumníku serveru nebo případně klikněte pravým tlačítkem na uloženou proceduru a zvolte Otevřít. Obrázek 13 znázorňuje uloženou proceduru Products_Delete při otevření.

Uložené procedury je možné otevřít a upravit v sadě Visual Studio.

Obrázek 13: Uložené procedury je možné otevřít a upravit v sadě Visual Studio (kliknutím zobrazíte obrázek v plné velikosti)

Obsah uložených procedur a Products_DeleteProducts_Select je poměrně jednoduchý. Naproti Products_Insert tomu uložené procedury a Products_Update vyžadují bližší kontrolu, protože obě provádějí SELECT prohlášení za svými INSERT prohlášeními a UPDATE . Uloženou proceduru tvoří Products_Insert například následující SQL:

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 a tyto hodnoty se používají v příkazu INSERT . Za příkazem INSERT se použije dotaz, který SELECT vrátí Products hodnoty 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 vlastnosti nově přidaných ProductRow instancí ProductID pomocí automaticky přidaných hodnot přiřazených databází.

Tuto funkci znázorňuje následující kód. Obsahuje ProductsTableAdapter a ProductsDataTable vytvořené pro NorthwindWithSprocs typed dataSet. Nový produkt se přidá do databáze tak, že se vytvoří ProductsRow instance, zadá se její hodnoty a zavolá metoda TableAdapter s Update předáním ProductsDataTablemetody . Interně TableAdapter s Update metoda vytvoří ProductsRow výčet instancí v předané DataTable (v tomto příkladu je 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 Products tabulky přidá nový záznam a vrátí podrobnosti o nově přidaném záznamu. Hodnota ProductsRow instance s ProductID se pak aktualizuje. Update Po dokončení metody můžeme získat přístup k nově přidané hodnotě záznamu ProductIDProductsRow prostřednictvím vlastnosti sProductID.

' 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 podobně obsahuje SELECT příkaz za svým 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 může dojít ke změně primárního klíče. Například v databázi zaměstnanců může každý záznam zaměstnance používat jako primární klíč číslo sociálního pojištění zaměstnance. Aby bylo možné změnit stávající číslo sociálního pojištění zaměstnance, musí být zadáno nové i původní číslo sociálního pojištění. Products Pro tabulku tato funkce není potřeba, protože ProductID sloupec je IDENTITY sloupec a nikdy by se neměl měnit. Příkaz v uložené proceduře Products_Update ve skutečnosti UPDATE neobsahuje ProductID sloupec v seznamu sloupců. I když @Original_ProductID se tedy používá v UPDATE klauzuli statement s WHERE , je pro Products tabulku nadbytečná a může být nahrazena parametrem @ProductID . Při úpravě parametrů uložené procedury je důležité, aby byly aktualizovány také metody TableAdapter, které tuto uloženou proceduru používají.

Krok 4: Úprava parametrů uložené procedury a aktualizace objektu TableAdapter

Vzhledem k tomu, že @Original_ProductID je parametr nadbytečný, pojďme ho Products_Update z uložené procedury úplně odebrat. Otevřete uloženou proceduru Products_Update@Original_ProductID , odstraňte parametr a v WHERE klauzuli UPDATE příkazu změňte použitý název parametru z @Original_ProductID na @ProductID. Po provedení těchto změn by měl T-SQL v rámci uložené procedury 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 panelu nástrojů na ikonu Uložit nebo stiskněte Ctrl+S. V tomto okamžiku Products_Update uložená procedura neočekává @Original_ProductID vstupní parametr, ale Objekt TableAdapter je nakonfigurován tak, aby takový parametr předal. Parametry, které objekt TableAdapter odešle uložené proceduřeProducts_Update, můžete zobrazit tak, že v Designer Datové sady vyberete objekt TableAdapter, přejdete na okno Vlastnosti a kliknete na tři tečky v kolekci UpdateCommand sParameters. Zobrazí se dialogové okno Kolekce parametrů Editor zobrazené na obrázku 14.

Kolekce parametrů Editor Seznamy použité parametry předané uložené proceduře Products_Update

Obrázek 14: Kolekce parametrů Editor Seznamy použitých parametrů předaných uložené proceduře Products_Update

Odsud můžete tento parametr odebrat jednoduše tak, že ho @Original_ProductID vyberete ze seznamu členů a kliknete na tlačítko Odebrat.

Alternativně můžete aktualizovat parametry používané pro všechny metody tak, že kliknete pravým tlačítkem na objekt TableAdapter v Designer a zvolíte Konfigurovat. Zobrazí se průvodce konfigurací tableadapter, který zobrazí seznam uložených procedur používaných pro výběr, vložení, aktualizaci a odstranění spolu s parametry, které uložené procedury očekávají. Když kliknete na rozevírací seznam Aktualizovat, zobrazí Products_Update se očekávané vstupní parametry uložených procedur, které už neobsahují @Original_ProductID (viz Obrázek 15). Jednoduše klikněte na Dokončit a automaticky aktualizujte kolekci parametrů používanou objektem TableAdapter.

Případně můžete použít Průvodce konfigurací objektu TableAdapter k aktualizaci kolekcí parametrů jeho metod.

Obrázek 15: Alternativně můžete použít Průvodce konfigurací nástroje TableAdapter k aktualizaci kolekcí 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 parametru TableAdapter je snadné nechat automaticky vygenerovat odpovídající uložené procedury. Totéž platí při přidávání dalších metod do objektu TableAdapter. Pro ilustraci přidáme metodu GetProductByProductID(productID) do objektu vytvořeného ProductsTableAdapter v kroku 2. Tato metoda vezme 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.

Přidání nového dotazu do vlastnosti TableAdapter

Obrázek 16: Přidání nového dotazu do vlastnosti TableAdapter

Tím se spustí Průvodce konfigurací dotazu TableAdapter, který nejprve zobrazí výzvu k přístupu k databázi pomocí parametru TableAdapter. Pokud chcete vytvořit novou uloženou proceduru, zvolte možnost Vytvořit novou uloženou proceduru a klikněte na Další.

Zvolte možnost Vytvořit novou uloženou proceduru.

Obrázek 17: Volba možnosti Vytvořit novou uloženou proceduru (kliknutím zobrazíte obrázek v plné velikosti)

Další obrazovka nás vyzve k určení typu dotazu, který se má provést, zda vrátí sadu řádků nebo jednu skalární hodnotu, nebo provede UPDATEpříkaz , INSERTnebo DELETE . Vzhledem k tomu, že GetProductByProductID(productID) metoda vrátí řádek, nechte vybranou možnost VYBRAT, která vrací řádek a stiskněte Další.

Zvolte možnost SELECT, která vrací řádek.

Obrázek 18: Výběr možnosti SELECT, která vrátí řádek (kliknutím zobrazíte obrázek v plné velikosti)

Na další obrazovce se zobrazí hlavní dotaz objektu TableAdapter, který uvádí pouze 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 produktů pro zadaný produkt:

SELECT ProductID, ProductName, SupplierID, CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued
FROM Products
WHERE ProductID = @ProductID

Nahraďte název uložené procedury dotazem SELECT.

Obrázek 19: Nahrazení názvu uložené procedury dotazem SELECT (kliknutím zobrazíte obrázek v plné velikosti)

Následující obrazovka vás vyzve k pojmenování uložené procedury, která se vytvoří. Zadejte název Products_SelectByProductID a klikněte na Další.

Pojmenujte novou uloženou proceduru Products_SelectByProductID

Obrázek 20: Pojmenujte novou uloženou proceduru Products_SelectByProductID (kliknutím zobrazíte obrázek v plné velikosti)

Poslední krok průvodce nám umožňuje změnit vygenerované názvy metod a určit, jestli se má použít vzor Vyplnit datovou tabulku, Vrátit vzor DataTable, nebo obojí. U této metody nechte zaškrtnuté obě možnosti, ale přejmenujte metody na FillByProductID a GetProductByProductID. Kliknutím na Tlačítko Další zobrazíte souhrn kroků, které průvodce provede, a kliknutím na Tlačítko Dokončit průvodce dokončete.

Přejmenujte metody TableAdapter na FillByProductID a GetProductByProductID.

Obrázek 21: Přejmenujte metody TableAdapter na FillByProductID a GetProductByProductID (Kliknutím zobrazíte obrázek v plné velikosti)

Po dokončení průvodce má Objekt TableAdapter k dispozici novou metodu, GetProductByProductID(productID) která při vyvolání spustí uloženou proceduru Products_SelectByProductID , která byla právě vytvořena. Chvíli si prohlédněte tuto novou uloženou proceduru v Průzkumníku 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 na složku Uložené procedury a zvolte Aktualizovat).

Všimněte si, že uložená SelectByProductID procedura přijímá @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šechny své volání do vrstvy obchodní logiky (BLL). Aby bylo možné dodržet toto rozhodnutí o návrhu, musíme nejprve vytvořit třídu BLL pro novou Typed DataSet, abychom měli přístup k datům produktu z prezentační vrstvy.

Ve složce vytvořte nový soubor třídy s názvem ProductsBLLWithSprocs.vb~/App_Code/BLL 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 ProductsBLL sémantiku třídy z předchozích kurzů, ale používá ProductsTableAdapter objekty a ProductsDataTable ze NorthwindWithSprocs sady DataSet. Například místo toho, aby na začátku souboru třídy měla Imports NorthwindTableAdapters příkaz jako , ProductsBLLWithSprocs třída používá Imports NorthwindWithSprocsTableAdapters.ProductsBLL Podobně ProductsDataTable objekty a ProductsRow použité v této třídě mají předponu NorthwindWithSprocs oboru názvů. Třída ProductsBLLWithSprocs poskytuje dvě metody přístupu k datům GetProducts , a GetProductByProductIDmetody a metody pro přidání, aktualizaci a odstranění jedné instance produktu.

Krok 7: Práce seNorthwindWithSprocssadou dat z prezentační vrstvy

V tomto okamžiku jsme vytvořili dal, který používá uložené procedury pro přístup k podkladovým datům databáze a jejich úpravu. Vytvořili jsme také základní metodu 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ů. Chcete-li tento kurz zaokrouhlit, pojďme vytvořit ASP.NET stránku, která používá třídu BLL s ProductsBLLWithSprocs k zobrazení, aktualizaci a odstraňování záznamů.

NewSprocs.aspx Otevřete stránku ve AdvancedDAL složce a přetáhněte objekt GridView z panelu nástrojů do Designer a pojměte ho Products. Z inteligentní značky GridView zvolte jeho vazbu na nový ObjectDataSource s názvem ProductsDataSource. Nakonfigurujte ObjectDataSource tak, aby používal třídu ProductsBLLWithSprocs , jak je znázorněno na obrázku 22.

Nakonfigurujte ObjectDataSource tak, aby používal třídu ProductsBLLWithSprocs.

Obrázek 22: Konfigurace objektu ObjectDataSource pro použití ProductsBLLWithSprocs třídy (kliknutím zobrazíte obrázek v plné velikosti)

Rozevírací seznam na kartě SELECT má dvě možnosti a GetProductsGetProductByProductID. 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 Dokončit.

Po dokončení průvodce ObjectDataSource přidá Visual Studio do pole GridView pro data produktu BoundFields a CheckBoxField. Zapněte předdefinované funkce pro úpravy a odstraňování v GridView zaškrtnutím možností Povolit úpravy a Povolit odstranění, které jsou přítomné v inteligentní značce.

Stránka obsahuje objekt GridView s povolenou podporou úprav a odstraňování.

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, sada Visual Studio nastaví OldValuesParameterFormatString po dokončení průvodce ObjectDataSource s vlastnost na original_{0}. Aby funkce pro úpravu dat fungovaly správně s parametry očekávanými metodami v naší BLL, musí se vrátit na výchozí hodnotu {0} . Proto nezapomeňte vlastnost nastavit OldValuesParameterFormatString na {0} nebo ji úplně odebrat z deklarativní syntaxe.

Po dokončení průvodce Konfigurovat zdroj dat, zapnutí úprav a odstranění podpory v GridView a vrácení vlastnosti ObjectDataSource s OldValuesParameterFormatString na výchozí hodnotu by deklarativní značky stránky měly 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 tomto okamžiku bychom mohli editovat GridView přizpůsobením rozhraní pro úpravy tak, aby zahrnovalo ověření, nechat CategoryID sloupce a SupplierID vykreslit jako DropDownLists atd. K tlačítku Odstranit bychom také mohli přidat potvrzení na straně klienta a doporučujeme vám, abyste si vzali čas na implementaci těchto vylepšení. Vzhledem k tomu, že tato témata byla popsána v předchozích kurzech, nebudeme je zde znovu probrat.

Bez ohledu na to, jestli gridview vylepšíte nebo ne, otestujte základní funkce stránky v prohlížeči. Jak ukazuje obrázek 24, stránka obsahuje seznam produktů v zobrazení GridView, který poskytuje možnosti pro úpravy a odstraňování jednotlivých řádků.

Produkty lze zobrazit, upravit a odstranit z GridView.

Obrázek 24: Produkty lze zobrazit, upravit a odstranit z GridView (kliknutím zobrazíte obrázek v plné velikosti)

Souhrn

TableAdaptery v typed dataset mají přístup k datům z databáze pomocí ad hoc příkazů SQL 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 může být instruován k vytvoření nových uložených procedur založených SELECT na dotazu. V tomto kurzu jsme prozkoumali, jak pro nás automaticky vytvořit uložené procedury.

Automatické vygenerování uložených procedur sice šetří čas, ale v některých případech není uložená procedura vytvořená průvodcem v souladu s tím, co bychom sami vytvořili. Jedním z příkladů je uložená Products_Update procedura, která očekávala vstupní parametry a i @Original_ProductID@ProductID když @Original_ProductID byl parametr nadbytečný.

V mnoha scénářích je možné, že uložené procedury již byly vytvořeny, nebo je můžeme chtít sestavit ručně, abychom měli větší úroveň kontroly 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 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ím recenzentem pro tento kurz byl Hilton Geisenow. Chcete si projít moje nadcházející články na WEBU MSDN? Pokud ano, dejte mi čáru na mitchell@4GuysFromRolla.comadresu .