Share via


Erstellen einer Datenzugriffsschicht (VB)

von Scott Mitchell

PDF herunterladen

In diesem Tutorial beginnen wir von Anfang an und erstellen die Data Access Layer (DAL) mithilfe von typisierten DataSets, um auf die Informationen in einer Datenbank zuzugreifen.

Einführung

Als Webentwickler dreht sich unser Leben um die Arbeit mit Daten. Wir erstellen Datenbanken, um die Daten zu speichern, Code zum Abrufen und Ändern sowie Webseiten, um sie zu sammeln und zusammenzufassen. Dies ist das erste Tutorial in einer langen Reihe, in dem Techniken zum Implementieren dieser gängigen Muster in ASP.NET 2.0 untersucht werden. Wir beginnen mit der Erstellung einer Softwarearchitektur , die aus einer Data Access Layer (DAL) mit typisierten DataSets, einer Business Logic Layer (BLL) besteht, die benutzerdefinierte Geschäftsregeln erzwingt, und einer Präsentationsebene, die aus ASP.NET Seiten besteht, die ein gemeinsames Seitenlayout verwenden. Nachdem diese Back-End-Vorarbeit gelegt wurde, werden wir mit der Berichterstellung fortfahren und zeigen, wie Daten aus einer Webanwendung angezeigt, zusammengefasst, gesammelt und überprüft werden. Diese Tutorials sind darauf ausgerichtet, präzise zu sein und schritt-für-Schritt-Anweisungen mit vielen Screenshots bereitzustellen, um Sie visuell durch den Prozess zu führen. Jedes Tutorial ist in C#- und Visual Basic-Versionen verfügbar und enthält einen Download des vollständigen verwendeten Codes. (Dieses erste Tutorial ist ziemlich langwierig, aber der Rest wird in viel verdaulicheren Blöcken dargestellt.)

Für diese Tutorials verwenden wir eine Microsoft SQL Server 2005 Express Edition Version der Northwind-Datenbank, die App_Data im Verzeichnis platziert ist. Zusätzlich zur Datenbankdatei enthält der App_Data Ordner auch die SQL-Skripts zum Erstellen der Datenbank, falls Sie eine andere Datenbankversion verwenden möchten. Wenn Sie eine andere SQL Server Version der Northwind-Datenbank verwenden, müssen Sie die NORTHWNDConnectionString Einstellung in der Datei der Anwendung Web.config aktualisieren. Die Webanwendung wurde mit Visual Studio 2005 Professional Edition als dateisystembasiertes Websiteprojekt erstellt. Alle Tutorials funktionieren jedoch genauso gut mit der kostenlosen Version von Visual Studio 2005, Visual Web Developer.

In diesem Tutorial beginnen wir von Anfang an und erstellen die Datenzugriffsebene (Data Access Layer, DAL), gefolgt von der Erstellung der Business Logic Layer (BLL) im zweiten Tutorial und arbeiten am Seitenlayout und der Navigation im dritten. Die Tutorials nach dem dritten werden auf dem Fundament aufbauen, das in den ersten drei jahren gelegt wurde. In diesem ersten Tutorial haben wir eine Menge zu behandeln, also starten Sie Visual Studio, und beginnen Sie mit dem Start!

Schritt 1: Erstellen eines Webprojekts und Herstellen einer Verbindung mit der Datenbank

Bevor wir unsere Data Access Layer (DAL) erstellen können, müssen wir zuerst eine Website erstellen und unsere Datenbank einrichten. Erstellen Sie zunächst eine neue dateisystembasierte ASP.NET-Website. Wechseln Sie dazu zum Menü Datei, und wählen Sie Neue Website aus, und zeigen Sie das Dialogfeld Neue Website an. Wählen Sie die Vorlage ASP.NET Website aus, legen Sie die Dropdownliste Speicherort auf Dateisystem fest, wählen Sie einen Ordner aus, um die Website zu platzieren, und legen Sie die Sprache auf Visual Basic fest.

Erstellen einer neuen Datei System-Based Website

Abbildung 1: Erstellen einer neuen Datei System-Based Website (Klicken Sie hier, um ein Bild in voller Größe anzuzeigen)

Dadurch wird eine neue Website mit einer Default.aspx ASP.NET Seite, einem App_Data Ordner und einer Web.config Datei erstellt.

Nachdem die Website erstellt wurde, besteht der nächste Schritt darin, einen Verweis auf die Datenbank im Server-Explorer von Visual Studio hinzuzufügen. Wenn Sie dem Server Explorer eine Datenbank hinzufügen, können Sie Tabellen, gespeicherte Prozeduren, Ansichten usw. in Visual Studio hinzufügen. Sie können auch Tabellendaten anzeigen oder ihre eigenen Abfragen manuell oder grafisch über den Abfrage-Generator erstellen. Darüber hinaus müssen wir beim Erstellen der typisierten DataSets für die DAL Visual Studio auf die Datenbank verweisen, aus der die typisierten DataSets erstellt werden sollen. Obwohl wir diese Verbindungsinformationen zu diesem Zeitpunkt bereitstellen können, füllt Visual Studio automatisch eine Dropdownliste der Datenbanken auf, die bereits im Server-Explorer registriert sind.

Die Schritte zum Hinzufügen der Northwind-Datenbank zum Server Explorer davon abhängig, ob Sie die SQL Server 2005 Express Edition-Datenbank im App_Data Ordner verwenden möchten oder ob Sie über ein Microsoft SQL Server 2000- oder 2005-Datenbankserversetup verfügen, das Sie stattdessen verwenden möchten.

Verwenden einer Datenbank imApp_DataOrdner

Wenn Sie nicht über einen SQL Server 2000- oder 2005-Datenbankserver verfügen, mit dem eine Verbindung hergestellt werden kann, oder Wenn Sie einfach vermeiden möchten, die Datenbank einem Datenbankserver hinzufügen zu müssen, können Sie die SQL Server 2005 Express Edition Version der Northwind-Datenbank verwenden, die sich im Ordner der heruntergeladenen App_Data Website befindet (NORTHWND.MDF).

Eine datenbank, die App_Data sich im Ordner befindet, wird dem Server Explorer automatisch hinzugefügt. Wenn Sie SQL Server 2005 Express Edition auf Ihrem Computer installiert haben, sollte ein Knoten namens NORTHWND angezeigt werden. MDF in der Server-Explorer, die Sie erweitern und die zugehörigen Tabellen, Ansichten, gespeicherten Prozeduren usw. erkunden können (siehe Abbildung 2).

Der App_Data Ordner kann auch Microsoft Access-Dateien .mdb enthalten, die wie ihre SQL Server Entsprechungen automatisch dem server-Explorer hinzugefügt werden. Wenn Sie keine der SQL Server Optionen verwenden möchten, können Sie die Northwind Traders-Datenbank und -Apps immer installieren und in das App_Data Verzeichnis wechseln. Beachten Sie jedoch, dass Access-Datenbanken nicht so funktionsreich sind wie SQL Server und nicht für die Verwendung in Websiteszenarien konzipiert sind. Darüber hinaus werden einige der über 35 Tutorials bestimmte Features auf Datenbankebene nutzen, die von Access nicht unterstützt werden.

Herstellen einer Verbindung mit der Datenbank in einem Microsoft SQL Server 2000- oder 2005-Datenbankserver

Alternativ können Sie eine Verbindung mit einer Northwind-Datenbank herstellen, die auf einem Datenbankserver installiert ist. Wenn auf dem Datenbankserver die Northwind-Datenbank noch nicht installiert ist, müssen Sie sie zunächst dem Datenbankserver hinzufügen, indem Sie das Installationsskript ausführen, das im Download dieses Tutorials enthalten ist.

Nachdem Sie die Datenbank installiert haben, wechseln Sie zum Explorer Server in Visual Studio, klicken Sie mit der rechten Maustaste auf den Knoten Daten Connections, und wählen Sie Verbindung hinzufügen aus. Wenn die Server-Explorer nicht angezeigt wird, wechseln Sie zum Explorer Ansicht/Server, oder drücken Sie STRG+ALT+S. Dadurch wird das Dialogfeld Verbindung hinzufügen geöffnet, in dem Sie den Server angeben können, mit dem eine Verbindung hergestellt werden soll, die Authentifizierungsinformationen und den Datenbanknamen. Nachdem Sie die Datenbankverbindungsinformationen erfolgreich konfiguriert und auf die Schaltfläche OK geklickt haben, wird die Datenbank als Knoten unter dem Knoten Daten Connections hinzugefügt. Sie können den Datenbankknoten erweitern, um seine Tabellen, Ansichten, gespeicherten Prozeduren usw. zu erkunden.

Hinzufügen einer Verbindung zur Northwind-Datenbank Ihres Datenbankservers

Abbildung 2: Hinzufügen einer Verbindung zur Northwind-Datenbank Ihres Datenbankservers

Schritt 2: Erstellen der Datenzugriffsebene

Beim Arbeiten mit Daten besteht eine Option darin, die datenspezifische Logik direkt in die Präsentationsebene einzubetten (in einer Webanwendung bilden die ASP.NET Seiten die Präsentationsebene). Dies kann in Form des Schreibens ADO.NET Codes in den Codeteil der ASP.NET Seite oder die Verwendung des SqlDataSource-Steuerelements aus dem Markupteil erfolgen. In beiden Fällen koppelt dieser Ansatz die Datenzugriffslogik eng mit der Präsentationsebene. Der empfohlene Ansatz besteht jedoch darin, die Datenzugriffslogik von der Präsentationsebene zu trennen. Diese separate Schicht wird als Datenzugriffsebene, kurz DAL, bezeichnet und wird in der Regel als separates Klassenbibliotheksprojekt implementiert. Die Vorteile dieser mehrschichtigen Architektur sind gut dokumentiert (informationen zu diesen Vorteilen finden Sie im Abschnitt "Weitere Lesungen" am Ende dieses Tutorials) und ist der Ansatz, den wir in dieser Reihe verfolgen werden.

Der gesamte Code, der für die zugrunde liegende Datenquelle spezifisch ist, z. B. das Herstellen einer Verbindung mit der Datenbank, das Ausgeben SELECTvon , INSERT, UPDATEund DELETE Befehlen usw., sollte sich in der DAL befinden. Die Präsentationsebene sollte keine Verweise auf diesen Datenzugriffscode enthalten, sondern stattdessen aufruft die DAL für alle Datenanforderungen. Datenzugriffsebenen enthalten in der Regel Methoden für den Zugriff auf die zugrunde liegenden Datenbankdaten. Die Northwind-Datenbank enthält Products beispielsweise Tabellen und Categories , in denen die Produkte zum Verkauf und die Kategorien, zu denen sie gehören, erfasst werden. In unserem DAL haben wir Methoden wie:

  • GetCategories(), dadurch werden Informationen zu allen Kategorien zurückgegeben.
  • GetProducts(), die Informationen zu allen Produkten zurückgibt
  • GetProductsByCategoryID(categoryID), das alle Produkte zurückgibt, die zu einer angegebenen Kategorie gehören
  • GetProductByProductID(productID), das Informationen zu einem bestimmten Produkt zurückgibt

Diese Methoden stellen beim Aufrufen eine Verbindung mit der Datenbank her, geben die entsprechende Abfrage aus und geben die Ergebnisse zurück. Wie wir diese Ergebnisse zurückgeben, ist wichtig. Diese Methoden können einfach ein DataSet oder DataReader zurückgeben, das von der Datenbankabfrage aufgefüllt wird, aber im Idealfall sollten diese Ergebnisse mithilfe von stark typisierten Objekten zurückgegeben werden. Ein stark typisiertes Objekt ist ein Objekt, dessen Schema zur Kompilierzeit starr definiert ist, während das gegenteilige Objekt, ein lose typisiertes Objekt, eines ist, dessen Schema bis zur Laufzeit nicht bekannt ist.

Der DataReader und das DataSet (standardmäßig) sind beispielsweise lose typisierte Objekte, da ihr Schema durch die Spalten definiert wird, die von der Datenbankabfrage zurückgegeben werden, die zum Auffüllen verwendet wird. Für den Zugriff auf eine bestimmte Spalte aus einer lose typisierten DataTable müssen Wir Syntax wie verwenden: DataTable.Rows(index)("columnName"). Die lose Eingabe der DataTable in diesem Beispiel zeigt sich darin, dass wir mithilfe einer Zeichenfolge oder eines Ordnungsindexes auf den Spaltennamen zugreifen müssen. Eine stark typisierte DataTable hingegen verfügt über jede ihrer Spalten als Eigenschaften, was zu Code führt, der wie folgt aussieht: DataTable.Rows(index).columnName.

Um stark typisierte Objekte zurückzugeben, können Entwickler entweder eigene benutzerdefinierte Geschäftsobjekte erstellen oder typisierte DataSets verwenden. Ein Geschäftsobjekt wird vom Entwickler als Klasse implementiert, deren Eigenschaften in der Regel die Spalten der zugrunde liegenden Datenbanktabelle widerspiegeln, die das Geschäftsobjekt darstellt. Ein typisiertes DataSet ist eine Klasse, die von Visual Studio basierend auf einem Datenbankschema für Sie generiert wird und deren Member gemäß diesem Schema stark typisiert sind. Das Typisierte DataSet selbst besteht aus Klassen, die die ADO.NET DataSet-, DataTable- und DataRow-Klassen erweitern. Zusätzlich zu stark typisierten DataTables enthalten Typed DataSets jetzt auch TableAdapters, bei denen es sich um Klassen mit Methoden zum Auffüllen der DataTables des DataSets und zum Weitergeben von Änderungen innerhalb der DataTables zurück an die Datenbank handelt.

Hinweis

Weitere Informationen zu den Vor- und Nachteilen der Verwendung von typisierten DataSets gegenüber benutzerdefinierten Geschäftsobjekten finden Sie unter Entwerfen von Datenebenenkomponenten und Übergeben von Datenebenenebenen.

Wir verwenden stark typisierte DataSets für die Architektur dieser Tutorials. Abbildung 3 veranschaulicht den Workflow zwischen den verschiedenen Ebenen einer Anwendung, die typisierte DataSets verwendet.

Der gesamte Datenzugriffscode wird an die DAL delegiert.

Abbildung 3: Der gesamte Datenzugriffscode wird der DAL zugewiesen (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Erstellen eines typisierten DataSet- und Tabellenadapters

Um mit dem Erstellen unserer DAL zu beginnen, fügen wir zunächst ein typisiertes DataSet zu unserem Projekt hinzu. Klicken Sie dazu mit der rechten Maustaste auf den Projektknoten im Projektmappen-Explorer, und wählen Sie Neues Element hinzufügen aus. Wählen Sie die Option DataSet aus der Liste der Vorlagen aus, und nennen Sie sie Northwind.xsd.

Wählen Sie ein neues DataSet zu Ihrem Projekt hinzufügen aus.

Abbildung 4: Wählen Sie aus, um Ihrem Projekt ein neues DataSet hinzuzufügen (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Nachdem Sie auf Hinzufügen geklickt haben, wählen Sie ja aus, wenn Sie aufgefordert werden, das DataSet zum App_Code Ordner hinzuzufügen. Die Designer für das typisierte DataSet wird dann angezeigt, und der TableAdapter-Konfigurations-Assistent wird gestartet, sodass Sie Ihren ersten TableAdapter zum typisierten DataSet hinzufügen können.

Ein typisiertes DataSet dient als stark typisierte Sammlung von Daten. Es besteht aus stark typisierten DataTable-Instanzen, die wiederum aus stark typisierten DataRow-Instanzen bestehen. Wir erstellen eine stark typisierte DataTable für jede zugrunde liegende Datenbanktabelle, mit der wir in dieser Tutorialsreihe arbeiten müssen. Beginnen wir mit dem Erstellen einer DataTable für die Products Tabelle.

Beachten Sie, dass stark typisierte DataTables keine Informationen zum Zugriff auf Daten aus der zugrunde liegenden Datenbanktabelle enthalten. Um die Daten abzurufen, um die DataTable aufzufüllen, verwenden wir eine TableAdapter-Klasse, die als Datenzugriffsebene fungiert. Für unsere Products DataTable enthält der TableAdapter die Methoden GetProducts(), GetProductByCategoryID(categoryID)usw., die von der Präsentationsebene aufgerufen werden. Die Rolle der DataTable besteht darin, als stark typisierte Objekte zu dienen, die zum Übergeben von Daten zwischen den Ebenen verwendet werden.

Der TableAdapter-Konfigurations-Assistent fordert Sie zunächst auf, die Datenbank auszuwählen, mit der Sie arbeiten möchten. In der Dropdownliste werden diese Datenbanken im serverbasierten Explorer angezeigt. Wenn Sie die Northwind-Datenbank nicht zum server-Explorer hinzugefügt haben, können Sie zu diesem Zeitpunkt auf die Schaltfläche Neue Verbindung klicken, um dies zu tun.

Wählen Sie die Northwind-Datenbank aus der Drop-Down-Liste aus.

Abbildung 5: Wählen Sie die Northwind-Datenbank aus der Drop-Down-Liste aus (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Nachdem Sie die Datenbank ausgewählt und auf Weiter geklickt haben, werden Sie gefragt, ob Sie den Verbindungszeichenfolge in der Web.config Datei speichern möchten. Wenn Sie die Verbindungszeichenfolge speichern, vermeiden Sie, dass sie in den TableAdapter-Klassen hart codiert wird, was die Dinge vereinfacht, wenn sich die Verbindungszeichenfolge Informationen in Zukunft ändern. Wenn Sie den Verbindungszeichenfolge in der Konfigurationsdatei speichern möchten, wird es im Abschnitt platziert, der zur Verbesserung der <connectionStrings> Sicherheit optional verschlüsselt oder später über die neue ASP.NET 2.0-Eigenschaftenseite innerhalb der IIS-GUI Admin-Tools geändert werden kann, was für Administratoren besser geeignet ist.

Speichern Sie die Verbindungszeichenfolge in Web.config

Abbildung 6: Speichern der Verbindungszeichenfolge in Web.config (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Als Nächstes müssen wir das Schema für die erste stark typisierte DataTable definieren und die erste Methode für unseren TableAdapter bereitstellen, die beim Auffüllen des stark typisierten DataSets verwendet werden soll. Diese beiden Schritte werden gleichzeitig ausgeführt, indem eine Abfrage erstellt wird, die die Spalten aus der Tabelle zurückgibt, die in unserer DataTable widerspiegelt werden soll. Am Ende des Assistenten geben wir dieser Abfrage einen Methodennamen. Sobald dies erreicht wurde, kann diese Methode von unserer Präsentationsebene aufgerufen werden. Die -Methode führt die definierte Abfrage aus und füllt eine stark typisierte DataTable auf.

Um mit der Definition der SQL-Abfrage zu beginnen, müssen wir zuerst angeben, wie der TableAdapter die Abfrage ausstellen soll. Wir können eine Ad-hoc-SQL-Anweisung verwenden, eine neue gespeicherte Prozedur erstellen oder eine vorhandene gespeicherte Prozedur verwenden. Für diese Tutorials verwenden wir Ad-hoc-SQL-Anweisungen.

Abfragen der Daten mithilfe einer Ad-hoc-SQL-Anweisung

Abbildung 7: Abfragen der Daten mithilfe einer Ad-hoc-SQL-Anweisung (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

An diesem Punkt können wir die SQL-Abfrage manuell eingeben. Beim Erstellen der ersten Methode im TableAdapter möchten Sie normalerweise, dass die Abfrage die Spalten zurückgibt, die in der entsprechenden DataTable ausgedrückt werden müssen. Dies können Sie erreichen, indem Sie eine Abfrage erstellen, die alle Spalten und alle Zeilen aus der Products Tabelle zurückgibt:

Geben Sie die SQL-Abfrage in das Textfeld ein.

Abbildung 8: Geben Sie die SQL-Abfrage in das Textfeld ein (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Alternativ können Sie den Abfrage-Generator verwenden und die Abfrage grafisch erstellen, wie in Abbildung 9 dargestellt.

Erstellen Sie die Abfrage grafisch über die Abfrage-Editor

Abbildung 9: Erstellen der Abfrage grafisch über die Abfrage-Editor (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Nachdem Sie die Abfrage erstellt haben, aber bevor Sie zum nächsten Bildschirm wechseln, klicken Sie auf die Schaltfläche Erweiterte Optionen. In Websiteprojekten ist "Insert-, Update- und Delete-Anweisungen generieren" die einzige erweiterte Option, die standardmäßig ausgewählt ist. Wenn Sie diesen Assistenten über eine Klassenbibliothek oder ein Windows-Projekt ausführen, wird auch die Option "Optimistische Parallelität verwenden" ausgewählt. Lassen Sie die Option "Optimistische Parallelität verwenden" vorerst deaktiviert. In zukünftigen Tutorials werden wir die optimistische Parallelität untersuchen.

Wählen Sie nur die Option Einfüge-, Update- und Delete-Anweisungen generieren aus.

Abbildung 10: Wählen Sie nur die Option Einfüge-, Update- und Delete-Anweisungen generieren aus (Klicken Sie, um das bild in voller Größe anzuzeigen)

Nachdem Sie die erweiterten Optionen überprüft haben, klicken Sie auf Weiter, um mit dem letzten Bildschirm fortzufahren. Hier werden wir aufgefordert, die Methoden auszuwählen, die dem TableAdapter hinzugefügt werden sollen. Es gibt zwei Muster zum Auffüllen von Daten:

  • Füllen Sie eine DataTable mit diesem Ansatz eine Methode, die eine DataTable als Parameter akzeptiert und basierend auf den Ergebnissen der Abfrage auffüllt. Die ADO.NET DataAdapter-Klasse implementiert dieses Muster beispielsweise mit ihrer Fill() -Methode.
  • Zurückgeben einer DataTable mit diesem Ansatz, den die Methode erstellt und füllt die DataTable für Sie und gibt sie als Rückgabewert der Methoden zurück.

Sie können vom TableAdapter eines oder beide dieser Muster implementieren lassen. Sie können die hier bereitgestellten Methoden auch umbenennen. Lassen Sie beide Kontrollkästchen aktiviert, auch wenn wir in diesen Tutorials nur das letztere Muster verwenden. Außerdem benennen wir die eher generische GetData Methode in um GetProducts.

Wenn aktiviert, erstellt Insert()das letzte Kontrollkästchen "GenerateDBDirectMethods", die Methoden , Update()und Delete() für den TableAdapter. Wenn Sie diese Option deaktiviert lassen, müssen alle Updates über die einzige Update() Methode des TableAdapter durchgeführt werden, die das Typisierte DataSet, eine DataTable, ein einzelnes DataRow oder ein Array von DataRows übernimmt. (Wenn Sie die Option "Einfüge-, Update- und Delete-Anweisungen generieren" in den erweiterten Eigenschaften in Abbildung 9 deaktiviert haben, hat diese Einstellung des Kontrollkästchens keine Auswirkung.) Lassen Sie dieses Kontrollkästchen aktiviert.

Ändern des Methodennamens von GetData in GetProducts

Abbildung 11: Ändern des Methodennamens von GetData in GetProducts (Klicken Sie, um das bild in voller Größe anzuzeigen)

Schließen Sie den Assistenten ab, indem Sie auf Fertig stellen klicken. Nachdem der Assistent geschlossen wurde, kehren wir zum DataSet-Designer zurück, in dem die soeben erstellte DataTable angezeigt wird. Sie können die Liste der Spalten in der Products DataTable (ProductID, ProductNameusw.) sowie die Methoden von ProductsTableAdapter (Fill() und GetProducts()) sehen.

Die Produkte DataTable und ProductsTableAdapter wurden dem typisierten DataSet hinzugefügt.

Abbildung 12: Die Products DataTable und ProductsTableAdapter wurden dem typisierten DataSet hinzugefügt (Klicken Sie, um das bild in voller Größe anzuzeigen)

An diesem Punkt verfügen wir über ein typisiertes DataSet mit einer einzelnen DataTable (Northwind.Products) und einer stark typisierten DataAdapter-Klasse (NorthwindTableAdapters.ProductsTableAdapter) mit einer GetProducts() -Methode. Diese Objekte können verwendet werden, um auf eine Liste aller Produkte über Code zuzugreifen, z. B.:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim products as Northwind.ProductsDataTable
products = productsAdapter.GetProducts()
For Each productRow As Northwind.ProductsRow In products
    Response.Write("Product: " & productRow.ProductName & "<br />")
Next

Dieser Code erforderte nicht, dass wir ein Bit datenzugriffsspezifischen Code schreiben mussten. Wir mussten keine ADO.NET Klassen instanziieren, wir mussten nicht auf Verbindungszeichenfolgen, SQL-Abfragen oder gespeicherte Prozeduren verweisen. Stattdessen stellt der TableAdapter den Code für den Datenzugriff auf niedriger Ebene für uns bereit.

Jedes in diesem Beispiel verwendete Objekt ist ebenfalls stark typisiert, sodass Visual Studio IntelliSense- und Kompilierzeittypüberprüfungen bereitstellen kann. Und am besten können die vom TableAdapter zurückgegebenen DataTables an ASP.NET Datenwebsteuerelemente gebunden werden, z. B. GridView, DetailsView, DropDownList, CheckBoxList und einige andere. Das folgende Beispiel veranschaulicht die Bindung der von der GetProducts() -Methode zurückgegebenen DataTable an eine GridView in nur drei Codezeilen innerhalb des Page_Load Ereignishandlers.

AllProducts.aspx

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="AllProducts.aspx.vb"
    Inherits="AllProducts" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>View All Products in a GridView</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>
            All Products</h1>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

AllProducts.aspx.vb

Imports NorthwindTableAdapters
Partial Class AllProducts
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles Me.Load
        Dim productsAdapter As New ProductsTableAdapter
        GridView1.DataSource = productsAdapter.GetProducts()
        GridView1.DataBind()
    End Sub
End Class

Die Liste der Produkte wird in einer GridView angezeigt.

Abbildung 13: Die Liste der Produkte wird in einer GridView angezeigt (Klicken Sie, um das bild in voller Größe anzuzeigen)

In diesem Beispiel mussten drei Codezeilen in den Ereignishandler unserer ASP.NET-Seite Page_Load geschrieben werden, in zukünftigen Tutorials wird jedoch untersucht, wie die ObjectDataSource zum deklarativen Abrufen der Daten aus der DAL verwendet werden kann. Mit der ObjectDataSource müssen wir keinen Code schreiben und erhalten auch Unterstützung für Paging und Sortierung!

Schritt 3: Hinzufügen parametrisierter Methoden zur Datenzugriffsebene

An diesem Punkt hat unsere ProductsTableAdapter Klasse nur eine Methode, GetProducts(), die alle Produkte in der Datenbank zurückgibt. Es ist zwar definitiv nützlich, mit allen Produkten arbeiten zu können, aber es gibt Zeiten, in denen wir Informationen zu einem bestimmten Produkt oder zu allen Produkten abrufen möchten, die zu einer bestimmten Kategorie gehören. Um diese Funktionalität unserer Datenzugriffsebene hinzuzufügen, können wir dem TableAdapter parametrisierte Methoden hinzufügen.

Fügen Sie die GetProductsByCategoryID(categoryID) -Methode hinzu. Um der DAL eine neue Methode hinzuzufügen, kehren Sie zum DataSet-Designer zurück, klicken Sie mit der rechten Maustaste in den ProductsTableAdapter Abschnitt, und wählen Sie Abfrage hinzufügen aus.

Klicken Sie mit der rechten Maustaste auf den TableAdapter, und wählen Sie Abfrage hinzufügen aus.

Abbildung 14: Right-Click auf dem TableAdapter und wählen Sie Abfrage hinzufügen aus.

Wir werden zuerst gefragt, ob wir mithilfe einer Ad-hoc-SQL-Anweisung oder einer neuen oder vorhandenen gespeicherten Prozedur auf die Datenbank zugreifen möchten. Verwenden Sie erneut eine Ad-hoc-SQL-Anweisung. Als Nächstes werden wir gefragt, welche Art von SQL-Abfrage wir verwenden möchten. Da wir alle Produkte zurückgeben möchten, die zu einer angegebenen Kategorie gehören, möchten wir eine SELECT Anweisung schreiben, die Zeilen zurückgibt.

Wählen Sie aus, um eine SELECT-Anweisung zu erstellen, die Zeilen zurückgibt.

Abbildung 15: Wählen Sie aus, um eine SELECT Anweisung zu erstellen, die Zeilen zurückgibt (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Im nächsten Schritt wird die SQL-Abfrage definiert, die für den Zugriff auf die Daten verwendet wird. Da wir nur die Produkte zurückgeben möchten, die zu einer bestimmten Kategorie gehören, verwende ich die gleiche SELECT Anweisung von GetProducts(), füge aber die folgende WHERE Klausel hinzu: WHERE CategoryID = @CategoryID. Der @CategoryID -Parameter gibt dem TableAdapter-Assistenten an, dass die von uns zu erstellende Methode einen Eingabeparameter des entsprechenden Typs erfordert (nämlich eine nullable ganze Zahl).

Geben Sie eine Abfrage ein, um nur Produkte in einer angegebenen Kategorie zurückzugeben.

Abbildung 16: Geben Sie eine Abfrage ein, um nur Produkte in einer angegebenen Kategorie zurückzugeben (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Im letzten Schritt können wir auswählen, welche Datenzugriffsmuster verwendet werden sollen, und die Namen der generierten Methoden anpassen. Für das Fill-Muster ändern wir den Namen in FillByCategoryID und für die Rückgabe eines DataTable-Rückgabemusters GetProductsByCategoryID(die GetX Methoden).

Wählen Sie die Namen für die TableAdapter-Methoden aus.

Abbildung 17: Auswählen der Namen für die TableAdapter-Methoden (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Nach Abschluss des Assistenten enthält das DataSet-Designer die neuen TableAdapter-Methoden.

Die Produkte können jetzt nach Kategorie abgefragt werden.

Abbildung 18: Die Produkte können jetzt nach Kategorie abgefragt werden.

Nehmen Sie sich einen Moment Zeit, um eine GetProductByProductID(productID) Methode mit derselben Technik hinzuzufügen.

Diese parametrisierten Abfragen können direkt aus dem DataSet-Designer getestet werden. Klicken Sie im TableAdapter mit der rechten Maustaste auf die -Methode, und wählen Sie Datenvorschau aus. Geben Sie als Nächstes die Werte ein, die für die Parameter verwendet werden sollen, und klicken Sie auf Vorschau.

Die Produkte, die zur Kategorie

Abbildung 19: Produkte, die zur Kategorie "Getränke" gehören, werden angezeigt (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Mit der GetProductsByCategoryID(categoryID) -Methode in unserem DAL können wir jetzt eine ASP.NET Seite erstellen, auf der nur die Produkte in einer angegebenen Kategorie angezeigt werden. Das folgende Beispiel zeigt alle Produkte, die in der Kategorie "Getränke" enthalten sind und über eine CategoryID von 1 verfügen.

Beverages.aspx

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Beverages.aspx.vb"
    Inherits="Beverages" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>Beverages</h1>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

Beverages.aspx.vb

Imports NorthwindTableAdapters
Partial Class Beverages
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles Me.Load
        Dim productsAdapter As New ProductsTableAdapter
        GridView1.DataSource =
         productsAdapter.GetProductsByCategoryID(1)
        GridView1.DataBind()
    End Sub
End Class

Die Produkte in der Kategorie

Abbildung 20: Diese Produkte in der Kategorie "Getränke" werden angezeigt (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Schritt 4: Einfügen, Aktualisieren und Löschen von Daten

Es gibt zwei Muster, die häufig zum Einfügen, Aktualisieren und Löschen von Daten verwendet werden. Das erste Muster, das ich als direktes Datenbankmuster aufrufe, umfasst das Erstellen von Methoden, die bei Aufruf einen INSERT- , UPDATE- oder DELETE -Befehl für die Datenbank ausgeben, die für einen einzelnen Datenbankdatensatz ausgeführt wird. Solche Methoden werden in der Regel in einer Reihe von Skalarwerten (ganze Zahlen, Zeichenfolgen, Boolesche Werte, DateTimes usw.) übergeben, die den einzufügenden, zu aktualisierenden oder zu löschenden Werten entsprechen. Bei diesem Muster für die Products Tabelle würde die delete-Methode beispielsweise einen ganzzahligen Parameter annehmen, der den ProductID des zu löschenden Datensatzes angibt, während die insert-Methode eine Zeichenfolge für , ein Dezimalzeichen für ProductName, UnitPriceeine ganze Zahl für usw UnitsOnStock.

Jede Einfüge-, Aktualisierungs- und Löschanforderung wird sofort an die Datenbank gesendet.

Abbildung 21: Jede Einfüge-, Aktualisierungs- und Löschanforderung wird sofort an die Datenbank gesendet (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Das andere Muster, das ich als Batchupdatemuster bezeichnen werde, besteht darin, ein gesamtes DataSet, DataTable oder eine Sammlung von DataRows in einem Methodenaufruf zu aktualisieren. Bei diesem Muster löscht, fügt ein Entwickler die DataRows in einer DataTable ein, fügt sie ein und ändert sie und übergibt dann diese DataRows oder DataTable an eine Updatemethode. Diese Methode listet dann die übergebenen DataRows auf, bestimmt, ob sie geändert, hinzugefügt oder gelöscht wurden (über den RowState-Eigenschaftswert von DataRow), und gibt die entsprechende Datenbankanforderung für jeden Datensatz aus.

Alle Änderungen werden mit der Datenbank synchronisiert, wenn die Update-Methode aufgerufen wird.

Abbildung 22: Alle Änderungen werden mit der Datenbank synchronisiert, wenn die Updatemethode aufgerufen wird (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Der TableAdapter verwendet standardmäßig das Batchaktualisierungsmuster, unterstützt aber auch das Direkte Db-Muster. Da wir beim Erstellen des TableAdapters die Option "Insert-, Update- und Delete-Anweisungen generieren" aus den erweiterten Eigenschaften ausgewählt haben, enthält die ProductsTableAdapter eine Update() -Methode, die das Batchaktualisierungsmuster implementiert. Insbesondere enthält der TableAdapter eine Update() Methode, die das typisierte DataSet, eine stark typisierte DataTable oder ein oder mehrere DataRows übergeben werden kann. Wenn Sie beim ersten Erstellen des TableAdapters das Kontrollkästchen "GenerateDBDirectMethods" aktiviert haben, wird das direkte DB-Muster auch über Insert()die Methoden , Update()und Delete() implementiert.

Beide Datenänderungsmuster verwenden die Eigenschaften , und von InsertCommandTableAdapter, um die INSERTBefehle , UPDATEund DELETE an die Datenbank auszugebenDeleteCommand. UpdateCommand Sie können die InsertCommandEigenschaften , UpdateCommandund DeleteCommand überprüfen und ändern, indem Sie im DataSet-Designer auf den TableAdapter klicken und dann zum Eigenschaftenfenster wechseln. (Stellen Sie sicher, dass Sie den TableAdapter ausgewählt haben und dass das ProductsTableAdapter Objekt das in der Dropdownliste im Eigenschaftenfenster ausgewählte Objekt ist.)

Der TableAdapter verfügt über die Eigenschaften InsertCommand, UpdateCommand und DeleteCommand.

Abbildung 23: Der TableAdapter verfügt über InsertCommanddie Eigenschaften , UpdateCommandund DeleteCommand (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Um eine dieser Datenbankbefehlseigenschaften zu überprüfen oder zu ändern, klicken Sie auf die CommandText Untereigenschaft, wodurch der Abfrage-Generator angezeigt wird.

Konfigurieren der INSERT-, UPDATE- und DELETE-Anweisungen im Abfrage-Generator

Abbildung 24: Konfigurieren der INSERTAnweisungen , UPDATEund DELETE im Abfrage-Generator (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Im folgenden Codebeispiel wird gezeigt, wie Sie das Batchupdatemuster verwenden, um den Preis aller Produkte zu verdoppeln, die nicht eingestellt werden und die mindestens 25 Einheiten vorrätig sind:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim products As Northwind.ProductsDataTable = productsAdapter.GetProducts()
For Each product As Northwind.ProductsRow In products
   If Not product.Discontinued AndAlso product.UnitsInStock <= 25 Then
      product.UnitPrice *= 2
   End if
Next
productsAdapter.Update(products)

Der folgende Code veranschaulicht, wie Sie das direkte Db-Muster verwenden, um ein bestimmtes Produkt programmgesteuert zu löschen, dann zu aktualisieren und dann ein neues hinzuzufügen:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
productsAdapter.Delete(3)
productsAdapter.Update( _
    "Chai", 1, 1, "10 boxes x 20 bags", 18.0, 39, 15, 10, false, 1)
productsAdapter.Insert( _
    "New Product", 1, 1, "12 tins per carton", 14.95, 15, 0, 10, false)

Erstellen benutzerdefinierter Einfüge-, Update- und Löschmethoden

Die Insert()von der direkten DB-Methode erstellten Methoden , Update()und Delete() können etwas umständlich sein, insbesondere für Tabellen mit vielen Spalten. Wenn Sie sich das vorherige Codebeispiel ansehen, ist ohne Hilfe von IntelliSense nicht besonders klar, welche Products Tabellenspalte den einzelnen Eingabeparametern den Update() Methoden und Insert() zugeordnet ist. Es kann vorkommen, dass wir nur eine oder zwei Spalten aktualisieren möchten oder eine benutzerdefinierte Insert() Methode benötigen, die möglicherweise den Wert des Felds (automatisches Inkrement) des neu eingefügten Datensatzes IDENTITY zurückgibt.

Um eine solche benutzerdefinierte Methode zu erstellen, kehren Sie zum DataSet-Designer zurück. Klicken Sie mit der rechten Maustaste auf tableAdapter, und wählen Sie Abfrage hinzufügen aus, und kehren Sie zum TableAdapter-Assistenten zurück. Auf dem zweiten Bildschirm können wir den Typ der zu erstellenden Abfrage angeben. Wir erstellen eine Methode, die ein neues Produkt hinzufügt und dann den Wert des neu hinzugefügten Datensatzes ProductIDzurückgibt. Wählen Sie daher das Erstellen einer INSERT Abfrage aus.

Erstellen einer Methode zum Hinzufügen einer neuen Zeile zur Tabelle

Abbildung 25: Erstellen einer Methode zum Hinzufügen einer neuen Zeile zur Products Tabelle (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Auf dem nächsten Bildschirm wird das InsertCommand-Element CommandText angezeigt. Erweitern Sie diese Abfrage, indem Sie am Ende der Abfrage hinzufügen SELECT SCOPE_IDENTITY() , wodurch der letzte Identitätswert zurückgegeben wird, der in eine IDENTITY Spalte im selben Bereich eingefügt wurde. (Weitere Informationen zu SCOPE_IDENTITY() und warum Sie SCOPE_IDENTITY() anstelle von @@IDENTITY verwenden möchten, finden Sie in dertechnischen Dokumentation.) Stellen Sie sicher, dass Sie die INSERT -Anweisung mit einem Semikolon beenden, bevor Sie die SELECT -Anweisung hinzufügen.

Erweitern sie die Abfrage, um den SCOPE_IDENTITY()-Wert zurückzugeben.

Abbildung 26: Erweitern der Abfrage, um den SCOPE_IDENTITY() Wert zurückzugeben (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Nennen Sie schließlich die neue Methode InsertProduct.

Legen Sie den Namen der neuen Methode auf InsertProduct fest.

Abbildung 27: Legen Sie den Namen der neuen Methode auf fest InsertProduct (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Wenn Sie zum DataSet-Designer sehen Sie, dass die eine ProductsTableAdapter neue Methode enthält, InsertProduct. Wenn diese neue Methode nicht über einen Parameter für jede Spalte in der Products Tabelle verfügt, haben Sie wahrscheinlich vergessen, die INSERT Anweisung mit einem Semikolon zu beenden. Konfigurieren Sie die InsertProduct -Methode, und stellen Sie sicher, dass Sie über ein Semikolon verfügen, das die INSERT -Anweisungen und SELECT -Anweisungen trennt.

Standardmäßig geben Insert-Methoden Nicht-Abfragemethoden aus, d. h., sie geben die Anzahl der betroffenen Zeilen zurück. Wir möchten jedoch, dass die InsertProduct -Methode den von der Abfrage zurückgegebenen Wert zurückgibt, nicht die Anzahl der betroffenen Zeilen. Um dies zu erreichen, passen Sie die -Eigenschaft der InsertProductExecuteMode -Methode an an Scalar.

Ändern der ExecuteMode-Eigenschaft in Skalar

Abbildung 28: Ändern der ExecuteMode Eigenschaft in Scalar (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Der folgende Code zeigt diese neue InsertProduct Methode in Aktion:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim new_productID As Integer = Convert.ToInt32(productsAdapter.InsertProduct( _
    "New Product", 1, 1, "12 tins per carton", 14.95, 10, 0, 10, false))
productsAdapter.Delete(new_productID)

Schritt 5: Abschließen der Datenzugriffsebene

Beachten Sie, dass die ProductsTableAdapters -Klasse die CategoryID Werte und SupplierID aus der Products Tabelle zurückgibt, aber nicht die CategoryName Spalte aus der Categories Tabelle oder die CompanyName Spalte aus der Suppliers Tabelle enthält, obwohl dies wahrscheinlich die Spalten sind, die beim Anzeigen von Produktinformationen angezeigt werden sollen. Wir können die anfängliche Methode des TableAdapters erweitern, GetProducts()um sowohl die Spaltenwerte als auch die CategoryName Spaltenwerte einzuschließen CompanyName . Dadurch wird die stark typisierte DataTable aktualisiert, um auch diese neuen Spalten einzuschließen.

Dies kann jedoch ein Problem darstellen, da die Methoden des TableAdapter zum Einfügen, Aktualisieren und Löschen von Daten auf dieser anfänglichen Methode basieren. Glücklicherweise sind die automatisch generierten Methoden zum Einfügen, Aktualisieren und Löschen von Unterabfragen in der SELECT -Klausel nicht betroffen. Indem wir darauf achten, dass wir unsere Abfragen Categories als Und Suppliers als Unterabfragen hinzufügen, vermeiden wir es, JOIN diese Methoden zum Ändern von Daten zu überarbeiten. Klicken Sie mit der rechten Maustaste auf die GetProducts() -Methode im , ProductsTableAdapter und wählen Sie Konfigurieren aus. Passen Sie dann die SELECT -Klausel so an, dass sie wie folgt aussieht:

SELECT     ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
(SELECT CategoryName FROM Categories
WHERE Categories.CategoryID = Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName
FROM         Products

Aktualisieren der SELECT-Anweisung für die GetProducts()-Methode

Abbildung 29: Aktualisieren der SELECT Anweisung für die GetProducts() -Methode (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Nach dem Aktualisieren der GetProducts() -Methode zur Verwendung dieser neuen Abfrage enthält die DataTable zwei neue Spalten: CategoryName und SupplierName.

Die Products DataTable verfügt über zwei neue Spalten.

Abbildung 30: Die Products DataTable enthält zwei neue Spalten

Nehmen Sie sich einen Moment Zeit, um auch die SELECT -Klausel in der GetProductsByCategoryID(categoryID) -Methode zu aktualisieren.

Wenn Sie die Syntax mithilfe JOIN der GetProducts()SELECT DataSet-Designer nicht automatisch die Methoden zum Einfügen, Aktualisieren und Löschen von Datenbankdaten mithilfe des direkten Datenbankmusters generieren können. Stattdessen müssen Sie sie manuell erstellen, ähnlich wie bei der InsertProduct Methode weiter oben in diesem Tutorial. Darüber hinaus müssen Sie die InsertCommandEigenschaftswerte , UpdateCommandund DeleteCommand manuell angeben, wenn Sie das Batchaktualisierungsmuster verwenden möchten.

Hinzufügen der verbleibenden TableAdapters

Bisher haben wir nur die Arbeit mit einem einzelnen TableAdapter für eine einzelne Datenbanktabelle untersucht. Die Northwind-Datenbank enthält jedoch mehrere verwandte Tabellen, mit denen wir in unserer Webanwendung arbeiten müssen. Ein typisiertes DataSet kann mehrere verwandte DataTables enthalten. Um unsere DAL abzuschließen, müssen wir daher DataTables für die anderen Tabellen hinzufügen, die wir in diesen Tutorials verwenden werden. Um einem typisierten DataSet einen neuen TableAdapter hinzuzufügen, öffnen Sie das DataSet-Designer, klicken Sie mit der rechten Maustaste in die Designer, und wählen Sie Hinzufügen/TableAdapter aus. Dadurch werden eine neue DataTable und TableAdapter erstellt und Sie durch den Assistenten führen, den wir weiter oben in diesem Tutorial untersucht haben.

Nehmen Sie sich einige Minuten Zeit, um die folgenden TableAdapters und -Methoden mithilfe der folgenden Abfragen zu erstellen. Beachten Sie, dass die Abfragen im ProductsTableAdapter die Unterabfragen enthalten, um die Kategorie- und Lieferantennamen der einzelnen Produkte zu erfassen. Wenn Sie außerdem folgen, haben Sie bereits die Methoden der ProductsTableAdapter -Klasse GetProducts() und GetProductsByCategoryID(categoryID) hinzugefügt.

  • ProductsTableAdapter

    • GetProducts:

      SELECT     ProductID, ProductName, SupplierID, 
      CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, 
      UnitsOnOrder, ReorderLevel, Discontinued, 
      (SELECT CategoryName FROM Categories WHERE
      Categories.CategoryID = Products.CategoryID) as 
      CategoryName, (SELECT CompanyName FROM Suppliers
      WHERE Suppliers.SupplierID = Products.SupplierID) 
      as SupplierName
      FROM         Products
      
    • GetProductsByCategoryID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName,
      (SELECT CompanyName FROM Suppliers WHERE
      Suppliers.SupplierID = Products.SupplierID)
      as SupplierName
      FROM         Products
      WHERE      CategoryID = @CategoryID
      
    • GetProductsBySupplierID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName, 
      (SELECT CompanyName FROM Suppliers WHERE 
      Suppliers.SupplierID = Products.SupplierID) as SupplierName
      FROM         Products
      WHERE SupplierID = @SupplierID
      
    • GetProductByProductID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName 
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName, 
      (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) 
      as SupplierName
      FROM         Products
      WHERE ProductID = @ProductID
      
  • CategoriesTableAdapter

    • GetCategories:

      SELECT     CategoryID, CategoryName, Description
      FROM         Categories
      
    • GetCategoryByCategoryID:

      SELECT     CategoryID, CategoryName, Description
      FROM         Categories
      WHERE CategoryID = @CategoryID
      
  • SuppliersTableAdapter

    • GetSuppliers:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      
    • GetSuppliersByCountry:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      WHERE Country = @Country
      
    • GetSupplierBySupplierID:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      WHERE SupplierID = @SupplierID
      
  • EmployeesTableAdapter

    • GetEmployees:

      SELECT     EmployeeID, LastName, FirstName, Title,
      HireDate, ReportsTo, Country
      FROM         Employees
      
    • GetEmployeesByManager:

      SELECT     EmployeeID, LastName, FirstName, Title, 
      HireDate, ReportsTo, Country
      FROM         Employees
      WHERE ReportsTo = @ManagerID
      
    • GetEmployeeByEmployeeID:

      SELECT     EmployeeID, LastName, FirstName, Title,
      HireDate, ReportsTo, Country
      FROM         Employees
      WHERE EmployeeID = @EmployeeID
      

Die DataSet-Designer, nachdem die vier TableAdapters hinzugefügt wurden

Abbildung 31: Das DataSet-Designer, nachdem die vier TableAdapters hinzugefügt wurden (Klicken Sie, um das bild in voller Größe anzuzeigen)

Hinzufügen von benutzerdefiniertem Code zur DAL

Die Dem Typd DataSet hinzugefügten TableAdapters und DataTables werden als XML-Schemadefinitionsdatei (Northwind.xsd) ausgedrückt. Sie können diese Schemainformationen anzeigen, indem Sie mit der rechten Maustaste auf die Northwind.xsd Datei im Projektmappen-Explorer klicken und Code anzeigen auswählen.

Die XML-Schemadefinitionsdatei (XSD) für das DataSet vom Typ Northwinds

Abbildung 32: Die XSD-Datei (XML Schema Definition) für das DataSet vom Typ Northwinds (Klicken Sie hier, um das bild in voller Größe anzuzeigen)

Diese Schemainformationen werden beim Kompilieren oder zur Laufzeit (falls erforderlich) in C#- oder Visual Basic-Code übersetzt. Ab diesem Zeitpunkt können Sie sie mit dem Debugger durchlaufen. Um diesen automatisch generierten Code anzuzeigen, wechseln Sie zur Klassenansicht, und führen Sie einen Drilldown zu den TableAdapter- oder Typed DataSet-Klassen durch. Wenn die Klassenansicht auf dem Bildschirm nicht angezeigt wird, wechseln Sie zum Menü Ansicht, und wählen Sie sie dort aus, oder drücken Sie STRG+UMSCHALT+C. In der Klassenansicht können Sie die Eigenschaften, Methoden und Ereignisse der Typed DataSet- und TableAdapter-Klassen sehen. Um den Code für eine bestimmte Methode anzuzeigen, doppelklicken Sie in der Klassenansicht auf den Methodennamen, oder klicken Sie mit der rechten Maustaste darauf, und wählen Sie Gehe zu Definition aus.

Überprüfen Sie den automatisch generierten Code, indem Sie in der Klassenansicht Zu Definition wechseln auswählen.

Abbildung 33: Überprüfen des automatisch generierten Codes durch Auswählen von Gehe zu Definition in der Klassenansicht

Während automatisch generierter Code eine große Zeitersparnis sein kann, ist der Code oft sehr generisch und muss angepasst werden, um die spezifischen Anforderungen einer Anwendung zu erfüllen. Das Risiko, automatisch generierten Code zu erweitern, besteht jedoch darin, dass das Tool, das den Code generiert hat, möglicherweise entscheidet, dass es an der Zeit ist, Ihre Anpassungen neu zu generieren und zu überschreiben. Mit dem neuen teilweisen Klassenkonzept von .NET 2.0 ist es einfach, eine Klasse auf mehrere Dateien aufzuteilen. Dadurch können wir unsere eigenen Methoden, Eigenschaften und Ereignisse den automatisch generierten Klassen hinzufügen, ohne dass Visual Studio unsere Anpassungen überschreiben muss.

Um das Anpassen der DAL zu veranschaulichen, fügen wir der SuppliersRow Klasse eine GetProducts() Methode hinzu. Die SuppliersRow -Klasse stellt einen einzelnen Datensatz in der Suppliers Tabelle dar. Jeder Lieferant kann null bis viele Produkte anbieten, sodass GetProducts() diese Produkte des angegebenen Lieferanten zurückgegeben werden. Erstellen Sie hierzu eine neue Klassendatei im App_Code Ordner namens, SuppliersRow.vb und fügen Sie den folgenden Code hinzu:

Imports NorthwindTableAdapters
Partial Public Class Northwind
    Partial Public Class SuppliersRow
        Public Function GetProducts() As Northwind.ProductsDataTable
            Dim productsAdapter As New ProductsTableAdapter
            Return productsAdapter.GetProductsBySupplierID(Me.SupplierID)
        End Function
    End Class
End Class

Diese partielle Klasse weist den Compiler an, dass beim Erstellen der -Klasse die Northwind.SuppliersRowGetProducts() soeben definierte Methode eingeschlossen wird. Wenn Sie Ihr Projekt erstellen und dann zur Klassenansicht zurückkehren, wird GetProducts() jetzt als Methode von Northwind.SuppliersRowaufgeführt.

Die GetProducts()-Methode ist jetzt Teil der Northwind.SuppliersRow-Klasse

Abbildung 34: Die GetProducts() -Methode ist jetzt Teil der Northwind.SuppliersRow -Klasse

Die GetProducts() -Methode kann nun verwendet werden, um den Satz von Produkten für einen bestimmten Lieferanten aufzulisten, wie der folgende Code zeigt:

Dim suppliersAdapter As New NorthwindTableAdapters.SuppliersTableAdapter()
Dim suppliers As Northwind.SuppliersDataTable = suppliersAdapter.GetSuppliers()
For Each supplier As Northwind.SuppliersRow In suppliers
    Response.Write("Supplier: " & supplier.CompanyName)
    Response.Write("<ul>")
    Dim products As Northwind.ProductsDataTable = supplier.GetProducts()
    For Each product As Northwind.ProductsRow In products
        Response.Write("<li>" & product.ProductName & "</li>")
    Next
    Response.Write("</ul><p> </p>")
Next

Diese Daten können auch in einer beliebigen ASP-Datei angezeigt werden. NET-Datenwebsteuerelemente. Auf der folgenden Seite wird ein GridView-Steuerelement mit zwei Feldern verwendet:

  • Ein BoundField,das den Namen der einzelnen Lieferanten anzeigt, und
  • Ein TemplateField-Steuerelement, das ein BulletedList-Steuerelement enthält, das an die von der -Methode für jeden GetProducts() Lieferanten zurückgegebenen Ergebnisse gebunden ist.

In zukünftigen Tutorials wird untersucht, wie Sie solche master-Detailberichte anzeigen können. Dieses Beispiel dient zur Veranschaulichung mithilfe der benutzerdefinierten Methode, die der Northwind.SuppliersRow Klasse hinzugefügt wurde.

SuppliersAndProducts.aspx

<%@ Page Language="VB" CodeFile="SuppliersAndProducts.aspx.vb"
    AutoEventWireup="true" Inherits="SuppliersAndProducts" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>
            Suppliers and Their Products</h1>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             AutoGenerateColumns="False"
             CssClass="DataWebControlStyle">
                <HeaderStyle CssClass="HeaderStyle" />
                <AlternatingRowStyle CssClass="AlternatingRowStyle" />
                <Columns>
                    <asp:BoundField DataField="CompanyName"
                      HeaderText="Supplier" />
                    <asp:TemplateField HeaderText="Products">
                        <ItemTemplate>
                            <asp:BulletedList ID="BulletedList1"
                             runat="server" DataSource="<%# CType(CType(Container.DataItem, System.Data.DataRowView).Row, Northwind.SuppliersRow).GetProducts() %>"
                                 DataTextField="ProductName">
                            </asp:BulletedList>
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

SuppliersAndProducts.aspx.vb

Imports NorthwindTableAdapters
Partial Class SuppliersAndProducts
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles Me.Load
        Dim suppliersAdapter As New SuppliersTableAdapter
        GridView1.DataSource = suppliersAdapter.GetSuppliers()
        GridView1.DataBind()
    End Sub
End Class

Der Firmenname des Lieferanten ist in der linken Spalte aufgeführt, seine Produkte rechts

Abbildung 35: Der Firmenname des Lieferanten ist in der linken Spalte aufgeführt, seine Produkte in der rechten Spalte (Klicken Sie, um das bild in voller Größe anzuzeigen)

Zusammenfassung

Beim Erstellen einer Webanwendung sollte das Erstellen der DAL einer Ihrer ersten Schritte sein, bevor Sie mit dem Erstellen der Präsentationsebene beginnen. Mit Visual Studio ist das Erstellen einer DAL basierend auf typisierten DataSets eine Aufgabe, die in 10 bis 15 Minuten ohne Schreiben einer Codezeile erledigt werden kann. Die Tutorials, die weiter voranschreiten, bauen auf diesem DAL auf. Im nächsten Tutorial definieren wir eine Reihe von Geschäftsregeln und erfahren, wie sie in einer separaten Geschäftslogikebene implementiert werden können.

Viel Spaß beim Programmieren!

Weitere Informationen

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

Videoschulungen zu Themen, die in diesem Tutorial enthalten sind

Zum Autor

Scott Mitchell, Autor von sieben ASP/ASP.NET-Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit 1998 mit Microsoft-Webtechnologien. Scott arbeitet als unabhängiger Berater, Trainer und Autor. Sein neuestes Buch ist Sams Teach Yourself ASP.NET 2.0 in 24 Stunden. Er kann unter mitchell@4GuysFromRolla.comoder über seinen Blog erreicht werden, der unter http://ScottOnWriting.NETzu finden ist.

Besonderen Dank an

Diese Tutorialreihe wurde von vielen hilfreichen Prüfern überprüft. Leitende Gutachter für dieses Tutorial waren Ron Green, Hilton Giesenow, Dennis Patterson, Liz Shulok, Abel Gomez und Carlos Santos. Möchten Sie meine anstehenden MSDN-Artikel lesen? Wenn dies der Fall ist, legen Sie eine Zeile unter abmitchell@4GuysFromRolla.com.