Freigeben über


Erstellen neuer Stored Procedures für die TableAdapter des Typed DataSet (VB)

von Scott Mitchell

PDF herunterladen

In früheren Lernprogrammen haben wir SQL-Anweisungen in unserem Code erstellt und die Anweisungen an die Datenbank übergeben, die ausgeführt werden sollen. Ein alternativer Ansatz besteht darin, gespeicherte Prozeduren zu verwenden, bei denen die SQL-Anweisungen in der Datenbank vordefiniert sind. In diesem Lernprogramm erfahren Sie, wie Sie mit dem TableAdapter-Assistenten neue gespeicherte Prozeduren für uns generieren können.

Einleitung

Die Datenzugriffsebene (Data Access Layer, DAL) für diese Lernprogramme verwendet Typed DataSets. Wie im Creating a Data Access Layer Tutorial erläutert, bestehen typisierte DataSets aus stark typisierten DataTables und TableAdapters. Die DataTables stellen die logischen Entitäten im System dar, während die TableAdapters mit der zugrunde liegenden Datenbank interagieren, um den Datenzugriff durchzuführen. Dazu gehört das Auffüllen der DataTables mit Daten, das Ausführen von Abfragen, die skalare Daten zurückgeben, und das Einfügen, Aktualisieren und Löschen von Datensätzen aus der Datenbank.

Die SQL-Befehle, die von den TableAdapters ausgeführt werden, können entweder ad-hoc-SQL-Anweisungen wie z. B. SELECT columnList FROM TableName oder gespeicherte Prozeduren sein. Die TableAdapters in unserer Architektur verwenden ad-hoc SQL-Anweisungen. Viele Entwickler und Datenbankadministratoren bevorzugen jedoch gespeicherte Prozeduren gegenüber Ad-hoc-SQL-Anweisungen aus Sicherheits-, Wartungs- und Updataability-Gründen. Andere bevorzugen ad-hoc SQL-Anweisungen eifrig für ihre Flexibilität. In meiner eigenen Arbeit favoriere ich gespeicherte Prozeduren gegenüber Ad-hoc-SQL-Anweisungen, aber entschied mich, ad-hoc SQL-Anweisungen zu verwenden, um die früheren Lernprogramme zu vereinfachen.

Wenn Sie ein TableAdapter-Objekt definieren oder neue Methoden hinzufügen, erleichtert der TableAdapter-Assistent das Erstellen neuer gespeicherter Prozeduren oder die Verwendung vorhandener gespeicherter Prozeduren wie die Verwendung von Ad-hoc-SQL-Anweisungen. In diesem Tutorial untersuchen wir, wie der Assistent des TableAdapter gespeicherte Prozeduren automatisch generiert. Im nächsten Lernprogramm erfahren Sie, wie Sie die TableAdapter-Methoden so konfigurieren, dass vorhandene oder manuell erstellte gespeicherte Prozeduren verwendet werden.

Hinweis

Sehen Sie sich Rob Howards Blogeintrag "Nicht schon gespeicherte Prozeduren verwenden?" und Frans Boumas Blogeintrag "Gespeicherte Prozeduren sind schlecht, oder M Kay?" an, um eine lebhafte Debatte über die Vor- und Nachteile gespeicherter Prozeduren und ad-hoc SQL zu führen.

Grundlagen der gespeicherten Prozedur

Funktionen sind ein Konstrukt, das allen Programmiersprachen gemeinsam ist. Eine Funktion ist eine Auflistung von Anweisungen, die ausgeführt werden, wenn die Funktion aufgerufen wird. Funktionen können Eingabeparameter akzeptieren und optional einen Wert zurückgeben. Gespeicherte Prozeduren sind Datenbankkonstrukte, die viele Ähnlichkeiten mit Funktionen in Programmiersprachen aufweisen. Eine gespeicherte Prozedur besteht aus einer Reihe von T-SQL-Anweisungen, die ausgeführt werden, wenn die gespeicherte Prozedur aufgerufen wird. Eine gespeicherte Prozedur akzeptiert möglicherweise null für viele Eingabeparameter und kann skalare Werte, Ausgabeparameter oder am häufigsten Resultsets aus SELECT Abfragen zurückgeben.

Hinweis

Gespeicherte Prozeduren werden häufig als sprocs oder SPs bezeichnet.

Gespeicherte Prozeduren werden mithilfe der CREATE PROCEDURE T-SQL-Anweisung erstellt. Das folgende T-SQL-Skript erstellt zum Beispiel eine gespeicherte Prozedur mit dem Namen GetProductsByCategoryID, die einen einzelnen Parameter mit dem Namen @CategoryID annimmt und die Felder ProductID, ProductName, UnitPrice und Discontinued der Spalten in der Products-Tabelle zurückgibt, die einen übereinstimmenden CategoryID-Wert aufweisen.

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

Nachdem diese gespeicherte Prozedur erstellt wurde, kann sie mithilfe der folgenden Syntax aufgerufen werden:

EXEC GetProductsByCategory categoryID

Hinweis

Im nächsten Lernprogramm untersuchen wir das Erstellen gespeicherter Prozeduren über die Visual Studio-IDE. In diesem Lernprogramm werden wir jedoch zulassen, dass der TableAdapter-Assistent automatisch die gespeicherten Prozeduren für uns generiert.

Zusätzlich zum einfachen Zurückgeben von Daten werden gespeicherte Prozeduren häufig verwendet, um mehrere Datenbankbefehle im Bereich einer einzelnen Transaktion auszuführen. Eine gespeicherte Prozedur mit dem Namen DeleteCategory, z. B. kann einen @CategoryID Parameter annehmen und zwei DELETE Anweisungen ausführen: zuerst, eine zum Löschen der zugehörigen Produkte und eine zweite, die die angegebene Kategorie löscht. Mehrere Anweisungen innerhalb einer gespeicherten Prozedur werden nicht automatisch in eine Transaktion eingeschlossen. Zusätzliche T-SQL-Befehle müssen ausgegeben werden, um sicherzustellen, dass die mehrere Befehle der gespeicherten Prozedur als atomer Vorgang behandelt werden. Im nächsten Tutorial sehen wir uns an, wie man die Befehle einer gespeicherten Prozedur im Bereich einer Transaktion umschließt.

Wenn Sie gespeicherte Prozeduren innerhalb einer Architektur verwenden, rufen die Methoden der Data Access Layer eine bestimmte gespeicherte Prozedur auf, anstatt eine Ad-hoc-SQL-Anweisung auszugeben. Dadurch wird der Speicherort der ausgeführten SQL-Anweisungen (in der Datenbank) zentralisiert, anstatt sie innerhalb der Anwendungsarchitektur definiert zu haben. Diese Zentralisierung erleichtert das Auffinden, Analysieren und Optimieren der Abfragen und bietet ein viel klareres Bild darüber, wo und wie die Datenbank verwendet wird.

Weitere Informationen zu den Grundlagen gespeicherter Prozeduren finden Sie im Abschnitt "Weiteres Lesen" am Ende dieses Lernprogramms.

Schritt 1: Erstellen der Webseiten für erweiterte Datenzugriffsschichtszenarien

Bevor wir mit der Erstellung eines DAL mit gespeicherte Prozeduren beginnen, nutzen wir die Gelegenheit, die ASP.NET-Seiten in unserem Webprojekt zu erstellen, die wir dafür und die nächsten Tutorials benötigen. Beginnen Sie mit dem Hinzufügen eines neuen Ordners mit dem Namen AdvancedDAL. Fügen Sie als Nächstes die folgenden ASP.NET Seiten zu diesem Ordner hinzu, und stellen Sie sicher, dass jede Seite der Site.master Gestaltungsvorlage zugeordnet wird:

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

Hinzufügen der ASP.NET Seiten für die Lernprogramme für erweiterte Datenzugriffsschichtszenarien

Abbildung 1: Hinzufügen der ASP.NET Seiten für die Lernprogramme für erweiterte Datenzugriffsschichtszenarien

Wie in den anderen Ordnern Default.aspx werden im AdvancedDAL Ordner die Tutorials im zugehörigen Abschnitt aufgelistet. Erinnern Sie sich daran, dass das SectionLevelTutorialListing.ascx Benutzersteuerelement diese Funktionalität bereitstellt. Fügen Sie dieses Benutzersteuerelement zu Default.aspx hinzu, indem Sie es aus dem Projektmappen-Explorer auf die Entwurfsansicht der Seite ziehen.

Hinzufügen des SectionLevelTutorialListing.ascx-Benutzersteuerelements zu Default.aspx

Abbildung 2: Hinzufügen des SectionLevelTutorialListing.ascx Benutzersteuerelements zu Default.aspx (Klicken, um das Bild in voller Größe anzuzeigen)

Fügen Sie diese Seiten schließlich als Einträge zur Web.sitemap Datei hinzu. Fügen Sie insbesondere das folgende Markup nach dem Arbeiten mit Batchdaten <siteMapNode>hinzu:

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

Nehmen Sie sich nach dem Aktualisieren Web.sitemap einen Moment Zeit, um die Tutorials-Website in einem Browser zu betrachten. Das Menü auf der linken Seite enthält jetzt Elemente für die lernprogramme für erweiterte DAL-Szenarien.

Die Websiteübersicht enthält jetzt Einträge für die Lernprogramme für erweiterte DAL-Szenarien.

Abbildung 3: Die Websiteübersicht enthält jetzt Einträge für die Lernprogramme für erweiterte DAL-Szenarien.

Schritt 2: Konfigurieren eines TableAdapters zum Erstellen neuer gespeicherter Prozeduren

Um das Erstellen einer Datenzugriffsebene zu veranschaulichen, die gespeicherte Prozeduren anstelle von Ad-hoc-SQL-Anweisungen verwendet, erstellen wir ein neues Typd DataSet im ~/App_Code/DAL Ordner namens NorthwindWithSprocs.xsd. Da wir diesen Prozess in früheren Lernprogrammen ausführlich durchlaufen haben, werden wir die hier beschriebenen Schritte schnell durchlaufen. Wenn Sie beim Erstellen und Konfigurieren eines typisierten DataSets auf Schwierigkeiten stoßen oder weitere schrittweise Anleitungen benötigen, können Sie das Lernprogramm "Erstellen einer Datenzugriffsschicht" erneut konsultieren.

Fügen Sie dem Projekt ein neues DataSet hinzu, indem Sie mit der rechten Maustaste auf den DAL Ordner klicken, "Neues Element hinzufügen" auswählen und die DataSet-Vorlage wie in Abbildung 4 dargestellt auswählen.

Fügen Sie ein neues typisiertes DataSet namens

Abbildung 4: Ein neues typisiertes DataSet mit dem Namen NorthwindWithSprocs.xsd zum Projekt hinzufügen (Klicken Sie, um das Bild in voller Größe anzusehen)

Dadurch wird das neue Typed DataSet erstellt, sein Designer geöffnet, ein neues TableAdapter erstellt und der TableAdapter-Konfigurations-Assistent gestartet. Der Erste Schritt des TableAdapter-Konfigurations-Assistenten fordert uns auf, die Datenbank auszuwählen, mit der sie arbeiten soll. Die Verbindungszeichenfolge zur Northwind-Datenbank sollte in der Dropdown-Liste aufgeführt werden. Wählen Sie dies aus, und klicken Sie auf "Weiter".

Auf diesem nächsten Bildschirm können wir auswählen, wie das TableAdapter-Objekt auf die Datenbank zugreifen soll. In früheren Lernprogrammen haben wir die erste Option "SQL-Anweisungen verwenden" ausgewählt. Wählen Sie für dieses Lernprogramm die zweite Option aus, erstellen Sie neue gespeicherte Prozeduren, und klicken Sie auf "Weiter".

Anweisen des TableAdapters zum Erstellen neuer gespeicherter Prozeduren

Abbildung 5: Weisen Sie "TableAdapter" an, neue gespeicherte Prozeduren zu erstellen (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Genau wie bei der Verwendung von Ad-hoc-SQL-Anweisungen werden wir im folgenden Schritt aufgefordert, die SELECT Anweisung für die TableAdapter-Hauptabfrage anzugeben. Anstatt jedoch die SELECT hier eingegebene Anweisung zum direkten Ausführen einer Ad-hoc-Abfrage zu verwenden, erstellt der TableAdapter-Assistent eine gespeicherte Prozedur, die diese SELECT Abfrage enthält.

Verwenden Sie die folgende SELECT Abfrage für diesen TableAdapter:

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

Eingeben der SELECT-Abfrage

Abbildung 6: Eingeben der SELECT Abfrage (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Hinweis

Die oben genannte Abfrage unterscheidet sich geringfügig von der Hauptabfrage des ProductsTableAdapter im Northwind typierten DataSet. Erinnern Sie sich daran, dass der ProductsTableAdapter Datensatztyp im Northwind zwei korrelierte Unterabfragen enthält, um den Kategorienamen und den Firmennamen für die Produktkategorie und jeden Lieferanten zurückzugeben. Im bevorstehenden Update des TableAdapter to Use JOINs-Lernprogramms werden wir uns ansehen, wie wir diese zugehörigen Daten zu diesem TableAdapter hinzufügen.

Nehmen Sie sich einen Moment Zeit, um auf die Schaltfläche "Erweiterte Optionen" zu klicken. Von hier aus können wir angeben, ob der Assistent auch Einfüge-, Update- und Löschanweisungen für den TableAdapter generieren soll, ob optimistische Parallelität verwendet werden soll und ob die Datentabelle nach Einfügungen und Aktualisierungen aktualisiert werden soll. Die Option "Einfüge-, Aktualisierungs- und Löschanweisungen generieren" ist standardmäßig aktiviert. Lassen Sie es aktiviert. Lassen Sie in diesem Tutorial die Option "Optimistische Parallelität verwenden" deaktiviert.

Wenn die gespeicherten Prozeduren automatisch vom TableAdapter-Assistenten erstellt werden, wird die Option "Datentabelle aktualisieren" ignoriert. Unabhängig davon, ob dieses Kontrollkästchen aktiviert ist, rufen die resultierenden einzufügenden und aktualisierten gespeicherten Prozeduren den just eingefügten oder just aktualisierten Datensatz ab, wie in Schritt 3 dargestellt.

Option

Abbildung 7: Option „Generieren von Einfüge-, Aktualisierungs- und Löschanweisungen aktiviert lassen“

Hinweis

Wenn die Option "Optimistische Parallelität verwenden" aktiviert ist, fügt der Assistent der WHERE Klausel zusätzliche Bedingungen hinzu, die verhindern, dass Daten aktualisiert werden, wenn Änderungen in anderen Feldern vorgenommen wurden. Weitere Informationen zur Verwendung des eingebauten Features zur optimistischen Parallelitätssteuerung des TableAdapters finden Sie im Tutorial zur Implementierung von Optimistischer Parallelität.

Nachdem Sie die SELECT Abfrage eingegeben und bestätigt haben, dass die Option "Einfügen", "Aktualisieren" und "Löschen" aktiviert ist, klicken Sie auf "Weiter". Dieser nächste Bildschirm, der in Abbildung 8 gezeigt wird, fordert die Namen der gespeicherten Prozeduren auf, die der Assistent zum Auswählen, Einfügen, Aktualisieren und Löschen von Daten erstellt. Ändern Sie die Namen dieser gespeicherten Prozeduren in Products_Select, , Products_Insert, Products_Updateund Products_Delete.

Umbenennen der gespeicherten Prozeduren

Abbildung 8: Umbenennen der gespeicherten Prozeduren (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Um das T-SQL zu sehen, das der TableAdapter-Assistent verwendet, um die vier gespeicherten Prozeduren zu erstellen, klicken Sie auf die Schaltfläche "SQL-Skriptvorschau". Im Dialogfeld "SQL-Skriptvorschau" können Sie das Skript in einer Datei speichern oder in die Zwischenablage kopieren.

Anzeigen einer Vorschau des ZUM Generieren der gespeicherten Prozeduren verwendeten SQL-Skripts

Abbildung 9: Anzeigen einer Vorschau des ZUM Generieren der gespeicherten Prozeduren verwendeten SQL-Skripts

Klicken Sie nach dem Benennen der gespeicherten Prozeduren auf "Weiter", um die entsprechenden Methoden des TableAdapters zu benennen. Genau wie bei der Verwendung von Ad-hoc-SQL-Anweisungen können wir Methoden erstellen, die eine vorhandene DataTable ausfüllen oder eine neue zurückgeben. Wir können auch angeben, ob das TableAdapter das DB-Direct Muster zum Einfügen, Aktualisieren und Löschen von Datensätzen enthalten soll. Lassen Sie alle drei Kontrollkästchen aktiviert, benennen Sie jedoch die Methode „Return a DataTable“ in GetProducts um, wie in Abbildung 10 zu sehen ist.

Benennen der Methoden Fill und GetProducts

Abbildung 10: Benennen sie die Methoden Fill und GetProducts (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Klicken Sie auf "Weiter", um eine Zusammenfassung der Schritte zu sehen, die der Assistent ausführen wird. Schließen Sie den Assistenten ab, indem Sie auf die Schaltfläche "Fertig stellen" klicken. Sobald der Assistent abgeschlossen ist, kehren Sie zum DataSet-Designer zurück, der jetzt die ProductsDataTable enthalten sollte.

Der DataSet-Designer zeigt die neu hinzugefügte ProductsDataTable an.

Abbildung 11: Der DataSet-Designer zeigt das neu hinzugefügte ProductsDataTable Bild an (Klicken, um das Bild in voller Größe anzuzeigen)

Schritt 3: Untersuchen der neu erstellten gespeicherten Prozeduren

Der in Schritt 2 verwendete TableAdapter-Assistent erstellt automatisch die gespeicherten Prozeduren zum Auswählen, Einfügen, Aktualisieren und Löschen von Daten. Diese gespeicherten Prozeduren können über Visual Studio angezeigt oder geändert werden, indem Sie zum Server-Explorer wechseln und einen Drilldown in den Ordner "Gespeicherte Prozeduren" der Datenbank ausführen. Wie in Abbildung 12 dargestellt, enthält die Northwind-Datenbank vier neue gespeicherte Prozeduren: Products_Delete, , , Products_InsertProducts_Selectund Products_Update.

Die vier gespeicherten Prozeduren, die in Schritt 2 erstellt wurden, finden Sie im Ordner

Abbildung 12: Die vier gespeicherten Prozeduren, die in Schritt 2 erstellt wurden, finden Sie im Ordner "Gespeicherte Prozeduren" der Datenbank.

Hinweis

Wenn der Server-Explorer nicht angezeigt wird, wechseln Sie zum Menü "Ansicht", und wählen Sie die Option "Server-Explorer" aus. Wenn die in Schritt 2 hinzugefügten produktbezogenen gespeicherten Prozeduren nicht angezeigt werden, klicken Sie mit der rechten Maustaste auf den Ordner "Gespeicherte Prozeduren", und wählen Sie "Aktualisieren" aus.

Um eine gespeicherte Prozedur anzuzeigen oder zu ändern, doppelklicken Sie im Server-Explorer auf den Namen, oder klicken Sie alternativ mit der rechten Maustaste auf die gespeicherte Prozedur, und wählen Sie "Öffnen" aus. Abbildung 13 zeigt die Products_Delete gespeicherte Prozedur beim Öffnen.

Gespeicherte Prozeduren können in Visual Studio geöffnet und geändert werden

Abbildung 13: Gespeicherte Prozeduren können in Visual Studio geöffnet und geändert werden (Klicken, um das Bild in voller Größe anzuzeigen)

Der Inhalt sowohl der Products_Delete- als auch der Products_Select-gespeicherten Prozeduren ist recht einfach zu verstehen. Die Products_Insert- und Products_Update-Prozeduren hingegen erfordern eine genauere Prüfung, da beide eine SELECT-Anweisung nach ihren INSERT- und UPDATE-Anweisungen ausführen. Die folgende SQL-Datei besteht beispielsweise aus der Products_Insert gespeicherten Prozedur:

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

Die gespeicherte Prozedur akzeptiert als Eingabeparameter die Spalten, die von der im TableAdapter-Assistenten angegebenen Abfrage Products zurückgegeben wurden, und diese Werte werden in einer SELECT Anweisung verwendet. Nach der INSERT Anweisung wird eine SELECT Abfrage verwendet, um die Products Spaltenwerte (einschließlich des ProductID) des neu hinzugefügten Datensatzes zurückzugeben. Diese Aktualisierungsfunktion ist hilfreich beim Hinzufügen eines neuen Datensatzes mithilfe des Batchaktualisierungsmusters, da die neu hinzugefügten ProductRowProductID Instanzeneigenschaften automatisch mit den automatisch erhöhten Werten aktualisiert werden, die der Datenbank zugewiesen wurden.

Der folgende Code veranschaulicht dieses Feature. Es enthält ein ProductsTableAdapter und ProductsDataTable erstellt für das typisierte NorthwindWithSprocs DataSet. Der Datenbank wird ein neues Produkt hinzugefügt, indem eine ProductsRow Instanz erstellt wird, deren Werte bereitgestellt werden. Die TableAdapter-Methode Update wird aufgerufen, wobei die ProductsDataTable übergeben wird. Intern listet die TableAdapter-Methode Update die ProductsRow Instanzen in der übergebenen DataTable auf (in diesem Beispiel gibt es nur eine - die gerade hinzugefügte) und führt den entsprechenden Einfüge-, Aktualisierungs- oder Löschbefehl aus. In diesem Fall wird die Products_Insert gespeicherte Prozedur ausgeführt, die der Products Tabelle einen neuen Datensatz hinzufügt und die Details des neu hinzugefügten Datensatzes zurückgibt. Der Wert der ProductsRow Instanz ProductID wird dann aktualisiert. Nachdem die Update Methode abgeschlossen wurde, können wir über die ProductID Eigenschaft s ProductsRow auf den neu hinzugefügten ProductID Datensatzwert zugreifen.

' 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

Die Products_Update gespeicherte Prozedur enthält ebenso eine SELECT Anweisung nach ihrer UPDATE Anweisung.

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)

Beachten Sie, dass diese gespeicherte Prozedur zwei Eingabeparameter für ProductID enthält: @Original_ProductID und @ProductID. Diese Funktionalität ermöglicht Szenarien, in denen der Primärschlüssel möglicherweise geändert wird. In einer Mitarbeiterdatenbank kann jeder Mitarbeiterdatensatz beispielsweise die Sozialversicherungsnummer des Mitarbeiters als Primärschlüssel verwenden. Um die Sozialversicherungsnummer eines vorhandenen Arbeitnehmers zu ändern, müssen sowohl die neue Sozialversicherungsnummer als auch die ursprüngliche nummer angegeben werden. Für die Products Tabelle ist diese Funktionalität nicht erforderlich, da es sich bei der ProductID Spalte um eine IDENTITY Spalte handelt und nie geändert werden sollte. Tatsächlich wird in der UPDATE Anweisung der Products_Update gespeicherten Prozedur die Spalte nicht in der ProductID Spaltenliste aufgeführt. Während @Original_ProductID in der UPDATE Anweisungsklausel WHERE verwendet wird, ist diese für die Products Tabelle überflüssig und könnte durch den @ProductID Parameter ersetzt werden. Beim Ändern der Parameter einer gespeicherten Prozedur ist es wichtig, dass auch die TableAdapter-Methode(n) aktualisiert wird, die diese gespeicherte Prozedur verwendet.

Schritt 4: Ändern der Parameter einer gespeicherten Prozedur und Aktualisieren des TableAdapter

Da der @Original_ProductID Parameter überflüssig ist, entfernen wir ihn vollständig aus der Products_Update gespeicherten Prozedur. Öffnen Sie die gespeicherte Prozedur Products_Update, löschen Sie den Parameter @Original_ProductID, und ändern Sie in der Klausel WHERE der Anweisung UPDATE den verwendeten Parameternamen von @Original_ProductID zu @ProductID. Nachdem Sie diese Änderungen vorgenommen haben, sollte die T-SQL innerhalb der gespeicherten Prozedur wie folgt aussehen:

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)

Wenn Sie diese Änderungen in der Datenbank speichern möchten, klicken Sie auf das Symbol "Speichern" in der Symbolleiste, oder drücken Sie STRG+S. Momentan erwartet die gespeicherte Prozedur Products_Update keinen Eingabeparameter, aber der TableAdapter ist so konfiguriert, dass ein solcher Parameter übergeben wird. Sie können die Parameter sehen, die der TableAdapter an die gespeicherte Prozedur Products_Update sendet, indem Sie den TableAdapter im DataSet-Designer auswählen, zum Eigenschaftenfenster wechseln und auf die Auslassungspunkte in der UpdateCommandParameters Sammlung klicken. Dadurch wird das Dialogfeld "Parametersammlungs-Editor" in Abbildung 14 angezeigt.

Der Parameterauflistungs-Editor listet die Parameter auf, die an die gespeicherte Prozedur Products_Update übergeben werden.

Abbildung 14: Der Parameter-Editor listet die Parameter auf, die an die gespeicherte Prozedur übergeben werden.

Sie können diesen Parameter hier entfernen, indem Sie einfach den @Original_ProductID Parameter aus der Liste der Mitglieder auswählen und auf die Schaltfläche "Entfernen" klicken.

Alternativ können Sie die für alle Methoden verwendeten Parameter aktualisieren, indem Sie im Designer mit der rechten Maustaste auf den TableAdapter klicken und dann "Konfigurieren" auswählen. Dadurch wird der TableAdapter-Konfigurations-Assistent geöffnet, welcher die gespeicherten Prozeduren für Auswahl, Einfügen, Aktualisieren und Löschen sowie die Parameter auflistet, die diese Prozeduren empfangen sollen. Wenn Sie auf die Dropdownliste "Aktualisieren" klicken, können Sie die erwarteten Eingabeparameter der Products_Update gespeicherten Prozeduren sehen, die nun @Original_ProductID nicht mehr enthalten (siehe Abbildung 15). Klicken Sie einfach auf "Fertig stellen", um die vom TableAdapter verwendete Parameterauflistung automatisch zu aktualisieren.

Alternativ können Sie den Konfigurations-Assistenten für TableAdapter verwenden, um die Methodenparameterauflistungen zu aktualisieren.

Abbildung 15: Sie können alternativ den Konfigurations-Assistenten für TableAdapter verwenden, um die Methodenparameterauflistungen zu aktualisieren (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Schritt 5: Hinzufügen zusätzlicher TableAdapter-Methoden

Wie Schritt 2 veranschaulicht, ist es beim Erstellen eines neuen TableAdapter einfach, die entsprechenden gespeicherten Prozeduren automatisch zu generieren. Das gleiche gilt beim Hinzufügen zusätzlicher Methoden zu einem TableAdapter. Um dies zu veranschaulichen, fügen wir der GetProductByProductID(productID) in Schritt 2 erstellten Methode eine ProductsTableAdapter Methode hinzu. Diese Methode verwendet als Eingabewert ProductID und gibt Details zum angegebenen Produkt zurück.

Klicken Sie zunächst mit der rechten Maustaste auf das TableAdapter-Objekt, und wählen Sie im Kontextmenü "Abfrage hinzufügen" aus.

Hinzufügen einer neuen Abfrage zum TableAdapter

Abbildung 16: Hinzufügen einer neuen Abfrage zum TableAdapter

Dadurch wird der Assistent zur Konfiguration der TableAdapter-Abfragen gestartet, der zuerst fragt, wie der TableAdapter auf die Datenbank zugreifen soll. Um eine neue gespeicherte Prozedur zu erstellen, wählen Sie die Option "Neue gespeicherte Prozedur erstellen" aus, und klicken Sie auf "Weiter".

Wählen Sie die Option

Abbildung 17: Auswählen der Option "Neue gespeicherte Prozedur erstellen" (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Der nächste Bildschirm fordert uns auf, den auszuführenden Abfragetyp zu identifizieren, ob er eine Zeilenmenge oder einen einzelnen skalaren Wert zurückgibt oder eine UPDATE, INSERT oder DELETE Anweisung ausführt. Da die GetProductByProductID(productID) Methode eine Zeile zurückgibt, behalten Sie die SELECT-Eigenschaft bei, die die Ausgewählte Zeilenoption zurückgibt, und drücken Sie "Weiter".

Wählen Sie das SELECT, das die Zeilenoption zurückgibt

Abbildung 18: Wählen Sie das SELECT, das die Zeilenoption zurückgibt (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Der nächste Bildschirm zeigt die TableAdapter-Hauptabfrage an, die nur den Namen der gespeicherten Prozedur (dbo.Products_Select) auflistet. Ersetzen Sie den Namen der gespeicherten Prozedur durch die folgende SELECT Anweisung, die alle Produktfelder für ein angegebenes Produkt zurückgibt:

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

Ersetzen des Namens der gespeicherten Prozedur durch eine SELECT-Abfrage

Abbildung 19: Ersetzen des Namens der gespeicherten Prozedur durch eine SELECT Abfrage (Klicken, um das Bild in voller Größe anzuzeigen)

Im folgenden Bildschirm werden Sie aufgefordert, die gespeicherte Prozedur zu benennen, die erstellt wird. Geben Sie den Namen Products_SelectByProductID ein, und klicken Sie auf "Weiter".

Benennen der neuen gespeicherten Prozedur Products_SelectByProductID

Abbildung 20: Benennen der neuen gespeicherten Prozedur Products_SelectByProductID (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Der letzte Schritt des Assistenten ermöglicht es uns, die generierten Methodennamen zu ändern und anzugeben, ob das Muster "Datentabelle ausfüllen", "DataTable-Muster zurückgeben" oder beides verwendet werden soll. Lassen Sie für diese Methode beide Optionen aktiviert, aber benennen Sie die Methoden in FillByProductID und GetProductByProductID um. Klicken Sie auf "Weiter", um eine Zusammenfassung der Schritte anzuzeigen, die der Assistent ausführt, und klicken Sie dann auf "Fertigstellen", um den Assistenten abzuschließen.

Benennen Sie die TableAdapter-Methoden in FillByProductID und GetProductByProductID um.

Abbildung 21: Umbenennen der TableAdapter-Methoden in FillByProductID und GetProductByProductID (Zum Anzeigen des Bilds mit voller Größe klicken)

Nach Abschluss des Assistenten steht dem TableAdapter eine neue Methode zur Verfügung, GetProductByProductID(productID), die die gerade erstellte gespeicherte Prozedur Products_SelectByProductID beim Aufrufen ausführt. Nehmen Sie sich einen Moment Zeit, um diese neue gespeicherte Prozedur aus dem Server-Explorer anzuzeigen, indem Sie in den Ordner "Gespeicherte Prozeduren" drillen und öffnen Products_SelectByProductID (wenn sie nicht angezeigt wird, klicken Sie mit der rechten Maustaste auf den Ordner "Gespeicherte Prozeduren", und wählen Sie "Aktualisieren" aus).

Beachten Sie, dass das gespeicherte Verfahren SelectByProductID den Eingabeparameter @ProductID verwendet und die Anweisung SELECT ausführt, die wir im Assistenten eingegeben haben.

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

Schritt 6: Erstellen einer Business Logic Layer-Klasse

In der gesamten Lernprogrammserie haben wir uns bemüht, eine mehrschichtige Architektur aufrechtzuerhalten, in der die Präsentationsschicht (Presentation Layer) alle ihre Aufrufe an die Geschäftslogikebene (Business Logic Layer, BLL) gerichtet hat. Um diese Entwurfsentscheidung einzuhalten, müssen wir zunächst eine BLL-Klasse für das neue Typd DataSet erstellen, bevor wir auf Produktdaten aus der Präsentationsebene zugreifen können.

Erstellen Sie eine neue Klassendatei namens ProductsBLLWithSprocs.vb im ~/App_Code/BLL Ordner, und fügen Sie sie dem folgenden Code hinzu:

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

Diese Klasse imitiert die ProductsBLL-Klassensemantik aus früheren Lernprogrammen, verwendet jedoch die ProductsTableAdapter und ProductsDataTable Objekte aus dem NorthwindWithSprocs DataSet. Statt z. B. eine Imports NorthwindTableAdapters Anweisung am Anfang der Klassendatei zu haben, wie ProductsBLL, verwendet die Klasse ProductsBLLWithSprocsImports NorthwindWithSprocsTableAdapters. Ebenso werden die in dieser Klasse verwendeten Objekte ProductsDataTable und ProductsRow mit dem Namespace NorthwindWithSprocs vorangestellt. Die ProductsBLLWithSprocs Klasse bietet zwei Methoden für den Datenzugriff GetProducts sowie GetProductByProductIDMethoden zum Hinzufügen, Aktualisieren und Löschen einer einzelnen Produktinstanz.

Schritt 7: Arbeiten mit demNorthwindWithSprocsDataSet aus der Präsentationsebene

An diesem Punkt haben wir eine DAL erstellt, die gespeicherte Prozeduren verwendet, um auf die zugrunde liegenden Datenbankdaten zuzugreifen und sie zu ändern. Wir haben auch eine rudimentäre BLL mit Methoden erstellt, um alle Produkte oder ein bestimmtes Produkt zusammen mit Methoden zum Hinzufügen, Aktualisieren und Löschen von Produkten abzurufen. Zum Abrunden dieses Lernprogramms erstellen wir eine ASP.NET Seite, die die BLL-Klasse ProductsBLLWithSprocs zum Anzeigen, Aktualisieren und Löschen von Datensätzen verwendet.

Öffnen Sie die NewSprocs.aspx Seite im AdvancedDAL Ordner, und ziehen Sie eine GridView aus der Toolbox auf den Designer, und nennen Sie sie Products. Wählen Sie das Smarttag der GridView und binden Sie es an eine neue ObjectDataSource mit dem Namen ProductsDataSource. Konfigurieren Sie die ObjectDataSource so, dass sie die ProductsBLLWithSprocs Klasse verwendet, wie in Abbildung 22 dargestellt.

Konfigurieren der ObjectDataSource für die Verwendung der ProductsBLLWithSprocs-Klasse

Abbildung 22: Konfigurieren der ObjectDataSource für die Verwendung der ProductsBLLWithSprocs Klasse (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Die Dropdownliste auf der Registerkarte SELECT verfügt über zwei Optionen: GetProducts und GetProductByProductID. Da wir alle Produkte in GridView anzeigen möchten, wählen Sie die GetProducts Methode aus. Die Dropdownlisten in den Registerkarten UPDATE, INSERT und DELETE weisen jeweils nur eine Methode auf. Stellen Sie sicher, dass jede dieser Dropdownlisten die entsprechende Methode ausgewählt hat, und klicken Sie dann auf "Fertig stellen".

Nachdem der ObjectDataSource-Assistent abgeschlossen wurde, fügt Visual Studio BoundFields und ein CheckBoxField zum GridView für die Produktdatenfelder hinzu. Aktivieren Sie die integrierten Funktionen zum Bearbeiten und Löschen von GridView, indem Sie die Optionen "Bearbeiten aktivieren" und "Löschen aktivieren" im Smarttag auswählen.

Die Seite enthält eine GridView mit aktivierter Bearbeitungs- und Löschunterstützung

Abbildung 23: Die Seite enthält eine GridView mit aktivierter Bearbeitungs- und Löschunterstützung (Klicken, um das Bild in voller Größe anzuzeigen)

Wie wir in früheren Tutoren besprochen haben, legt Visual Studio nach Abschluss des Assistenten für ObjectDataSource die OldValuesParameterFormatString Eigenschaft auf original_{0} fest. Dies muss auf den Standardwert {0} zurückgesetzt werden, damit die Funktionen zur Datenänderung ordnungsgemäß funktionieren, wenn die von den Methoden in unserer BLL erwarteten Parameter vorliegen. Stellen Sie daher sicher, dass die OldValuesParameterFormatString-Eigenschaft auf {0} festgelegt oder vollständig aus der deklarativen Syntax entfernt wird.

Nachdem Sie den Assistenten zum Konfigurieren von Datenquellen abgeschlossen haben, die Bearbeitungs- und Löschfunktionen in GridView aktivieren und die OldValuesParameterFormatString-Eigenschaft von ObjectDataSource auf ihren Standardwert zurücksetzen, sollte das deklarative Markup Ihrer Seite wie folgt aussehen:

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

An diesem Punkt könnten wir die GridView aufräumen, indem wir die Bearbeitungsschnittstelle anpassen, einschließlich Validierung, und die CategoryID- und SupplierID-Spalten als DropDownLists rendern lassen usw. Wir könnten auch eine clientseitige Bestätigung zur Schaltfläche "Löschen" hinzufügen, und ich möchte Sie ermutigen, die Zeit zu nehmen, diese Verbesserungen zu implementieren. Da diese Themen in früheren Lernprogrammen behandelt wurden, werden wir sie hier jedoch nicht wieder behandeln.

Unabhängig davon, ob Sie die GridView verbessern oder nicht, testen Sie die Kernfunktionen der Seite in einem Browser. Wie in Abbildung 24 dargestellt, listet die Seite die Produkte in einer GridView auf, die die Bearbeitungs- und Löschfunktionen pro Zeile bereitstellt.

Die Produkte können angezeigt, bearbeitet und aus der GridView gelöscht werden.

Abbildung 24: Die Produkte können aus der GridView angezeigt, bearbeitet und gelöscht werden (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Zusammenfassung

Die TableAdapter in einem typisierten DataSet können auf Daten aus der Datenbank zugreifen, indem sie ad-hoc-SQL-Anweisungen oder gespeicherte Prozeduren verwenden. Beim Arbeiten mit gespeicherten Prozeduren können vorhandene gespeicherte Prozeduren verwendet werden, oder der TableAdapter-Assistent kann angewiesen werden, neue gespeicherte Prozeduren basierend auf einer SELECT Abfrage zu erstellen. In diesem Lernprogramm haben wir untersucht, wie die gespeicherten Prozeduren automatisch für uns erstellt werden.

Das automatische Generieren der gespeicherten Prozeduren hilft Zeit zu sparen, aber es gibt bestimmte Fälle, in denen die vom Assistenten erstellte gespeicherte Prozedur nicht übereinstimmt mit dem, was wir selbst erstellt hätten. Ein Beispiel ist die Products_Update gespeicherte Prozedur, die sowohl Eingabeparameter @Original_ProductID als auch @ProductID erwartete, obwohl der @Original_ProductID Parameter überflüssig war.

In vielen Szenarien wurden die gespeicherten Prozeduren möglicherweise bereits erstellt, oder wir möchten sie manuell erstellen, um eine bessere Kontrolle über die Befehle der gespeicherten Prozedur zu erhalten. In beiden Fällen möchten wir das TableAdapter anweisen, vorhandene gespeicherte Prozeduren für seine Methoden zu verwenden. Wir werden sehen, wie dies im nächsten Lernprogramm zu erreichen ist.

Glückliche Programmierung!

Weitere nützliche Informationen

Weitere Informationen zu den in diesem Lernprogramm erläuterten Themen finden Sie in den folgenden Ressourcen:

Zum Autor

Scott Mitchell, Autor von sieben ASP/ASP.NET Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft Web Technologies zusammen. Scott arbeitet als unabhängiger Berater, Trainer und Schriftsteller. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 2.0 in 24 Stunden. Er kann bei mitchell@4GuysFromRolla.comerreicht werden.

Besonderer Dank an

Diese Lernprogrammreihe wurde von vielen hilfreichen Prüfern überprüft. Leitender Prüfer für dieses Lernprogramm war Hilton Geisenow. Möchten Sie meine bevorstehenden MSDN-Artikel überprüfen? Wenn ja, schicken Sie mir eine Nachricht an mitchell@4GuysFromRolla.com.