Freigeben über


Erstellen einer Datenzugriffsschicht (VB)

von Scott Mitchell

PDF herunterladen

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

Einführung

Als Webentwickler dreht sich unser Leben um das Arbeiten mit Daten. Wir erstellen Datenbanken zum Speichern der Daten, des Codes zum Abrufen und Ändern der Daten sowie webseiten, um sie zu sammeln und zusammenzufassen. Dies ist das erste Lernprogramm in einer langen Reihe, die Techniken für die Implementierung dieser allgemeinen Muster in ASP.NET 2.0 untersucht. Wir beginnen mit dem Erstellen einer Softwarearchitektur , die aus einer Data Access Layer (DAL) mit typierten DataSets, einer Geschäftslogikebene (Business Logic Layer, BLL) besteht, die benutzerdefinierte Geschäftsregeln erzwingt, und einer Präsentationsebene, die aus ASP.NET Seiten besteht, die ein gemeinsames Seitenlayout aufweisen. Sobald diese Back-End-Grundlagen festgelegt wurden, werden wir in die Berichterstellung übergehen und zeigen, wie Daten aus einer Webanwendung angezeigt, zusammengefasst, gesammelt und überprüft werden. Diese Lernprogramme sind darauf ausgerichtet, präzise zu sein und schrittweise Anleitungen mit vielen Screenshots bereitzustellen, um Sie visuell durch den Prozess zu führen. Jedes Lernprogramm ist in C#- und Visual Basic-Versionen verfügbar und enthält einen Download des vollständigen verwendeten Codes. (Dieses erste Lernprogramm ist ziemlich langwierig, aber der Rest wird in viel mehr digestiblen Blöcken dargestellt.)

Für diese Lernprogramme 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 Lernprogramme funktionieren jedoch genauso gut mit der kostenlosen Version von Visual Studio 2005, Visual Web Developer.

In diesem Lernprogramm beginnen wir von Anfang an und erstellen die Data Access Layer (DAL), gefolgt von der Erstellung der Business Logic Layer (BLL) im zweiten Lernprogramm und arbeiten an Seitenlayout und Navigation im dritten. Die Lernprogramme nach dem dritten werden auf dem Fundament aufbauen, das in den ersten drei gelegt wurde. Wir haben viel zu behandeln in diesem ersten Lernprogramm, feuern Sie Also Visual Studio aus, und lassen Sie uns loslegen!

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 ASP.NET-Websitevorlage aus, legen Sie die Dropdownliste "Speicherort" auf "Dateisystem" fest, wählen Sie einen Ordner aus, in dem die Website platziert werden soll, und legen Sie die Sprache auf Visual Basic fest.

Erstellen einer neuen dateisystembasierten Website

Abbildung 1: Erstellen einer neuen dateisystembasierten Website (Klicken Sie hier, um das 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. Durch Hinzufügen einer Datenbank zum Server-Explorer können Sie Tabellen, gespeicherte Prozeduren, Ansichten usw. aus Visual Studio hinzufügen. Sie können tabellendaten auch anzeigen oder eigene Abfragen entweder manuell oder grafisch über den Abfrage-Generator erstellen. Darüber hinaus müssen wir beim Erstellen der typierten DataSets für die DAL Visual Studio auf die Datenbank verweisen, aus der die typierten DataSets erstellt werden sollen. Während 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 hängen davon ab, ob Sie stattdessen 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 soll, oder Sie einfach vermeiden möchten, dass Sie die Datenbank einem Datenbankserver hinzufügen müssen, können Sie die SQL Server 2005 Express Edition-Version der Northwind-Datenbank verwenden, die sich im Ordner der heruntergeladenen Website App_Data befindet (NORTHWND.MDF).

Dem Server-Explorer wird automatisch eine Datenbank hinzugefügt, die App_Data im Ordner platziert wird. Angenommen, Sie haben SQL Server 2005 Express Edition auf Ihrem Computer installiert, sollte ein Knoten namens NORTHWND angezeigt werden. MDF im Server-Explorer, den Sie ihre Tabellen, Ansichten, gespeicherte Prozedur usw. erweitern und erkunden können (siehe Abbildung 2).

Der App_Data Ordner kann auch Microsoft Access-Dateien .mdb enthalten, die wie ihre SQL Server-Entsprechungen automatisch zum 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 ablegen. Beachten Sie jedoch, dass Access-Datenbanken nicht so funktionsreich wie SQL Server sind und nicht für die Verwendung in Websiteszenarien konzipiert sind. Darüber hinaus werden einige der 35 Lernprogramme 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 der Datenbankserver die Northwind-Datenbank noch nicht installiert hat, müssen Sie sie zuerst auf dem Datenbankserver hinzufügen, indem Sie das Installationsskript ausführen, das im Download dieses Lernprogramms enthalten ist.

Nachdem Sie die Datenbank installiert haben, wechseln Sie zum Server-Explorer in Visual Studio, klicken Sie mit der rechten Maustaste auf den Knoten "Datenverbindungen", und wählen Sie "Verbindung hinzufügen" aus. Wenn der Server-Explorer nicht angezeigt wird, wechseln Sie zum Ansichts-/Server-Explorer, oder drücken Sie STRG+ALT+S. Dadurch wird das Dialogfeld "Verbindung hinzufügen" angezeigt, in dem Sie den Server angeben können, mit dem eine Verbindung hergestellt werden soll, mit den Authentifizierungsinformationen und dem Datenbanknamen. Nachdem Sie die Datenbankverbindungsinformationen erfolgreich konfiguriert und auf die Schaltfläche "OK" geklickt haben, wird die Datenbank unter dem Knoten "Datenverbindungen" als Knoten 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 die Form des Schreibens ADO.NET Codes im Codeteil der ASP.NET Seite oder die Verwendung des SqlDataSource-Steuerelements aus dem Markupteil sein. 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 Ebene wird kurz als Datenzugriffsschicht( DAL) bezeichnet und wird in der Regel als separates Klassenbibliotheksprojekt implementiert. Die Vorteile dieser mehrschichtigen Architektur sind gut dokumentiert (siehe Abschnitt "Weitere Lesungen" am Ende dieses Lernprogramms, um Informationen zu diesen Vorteilen zu erhalten) und ist der Ansatz, den wir in dieser Reihe einnehmen werden.

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

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

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

Beispielsweise sind DataReader und DataSet (standardmäßig) lose typierte Objekte, da ihr Schema durch die spalten definiert wird, die von der Datenbankabfrage zurückgegeben werden, die zum Auffüllen verwendet wird. Um über eine lose typierte DataTable auf eine bestimmte Spalte zuzugreifen, müssen wir syntax wie folgt verwenden: DataTable.Rows(index)("columnName"). Die lose Eingabe der DataTable in diesem Beispiel ist durch die Tatsache dargestellt, dass wir mithilfe einer Zeichenfolge oder eines Ordnungsindex auf den Spaltennamen zugreifen müssen. Eine stark typierte DataTable hingegen wird jede der Spalten als Eigenschaften implementiert, was zu Code führt, der wie folgt aussieht: DataTable.Rows(index).columnName

Um stark typierte Objekte zurückzugeben, können Entwickler entweder eigene benutzerdefinierte Geschäftsobjekte erstellen oder Typed 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 typiertes DataSet ist eine Klasse, die von Visual Studio basierend auf einem Datenbankschema generiert wird und deren Member gemäß diesem Schema stark typiert sind. Das Typed DataSet selbst besteht aus Klassen, die die ADO.NET DataSet-, DataTable- und DataRow-Klassen erweitern. Zusätzlich zu stark typierten DataTables enthalten typierte DataSets jetzt auch TableAdapters, die Klassen mit Methoden zum Auffüllen der DataTables des DataSets und zum Verteilen von Änderungen innerhalb der DataTables zurück an die Datenbank sind.

Hinweis

Weitere Informationen zu den Vor- und Nachteilen der Verwendung von Typed DataSets im Vergleich zu benutzerdefinierten Geschäftsobjekten finden Sie unter Entwerfen von Datenebenenkomponenten und Übergeben von Daten über Ebenen.

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

Der gesamte Datenzugriffscode wird an den DAL delegiert.

Abbildung 3: Der gesamte Datenzugriffscode wird an die DAL delegiert (Klicken Sie hier, um das Bild mit voller Größe anzuzeigen)

Erstellen eines typierten DataSet- und Tabellenadapters

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

Wählen Sie das Hinzufügen eines neuen DataSets zu Ihrem Projekt aus.

Abbildung 4: Auswählen des Hinzufügens eines neuen DataSets zu Ihrem Projekt (Klicken Sie hier, um das Bild mit 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. Der Designer für das typierte DataSet wird dann angezeigt, und der TableAdapter-Konfigurations-Assistent wird gestartet, sodass Sie Das erste TableAdapter-Objekt dem typierten DataSet hinzufügen können.

Ein Typd DataSet dient als stark typierte Sammlung von Daten; sie besteht aus stark typierten DataTable-Instanzen, von denen jede wiederum aus stark typierten DataRow-Instanzen besteht. Wir erstellen eine stark typierte DataTable für jede zugrunde liegende Datenbanktabelle, mit der wir in dieser Lernprogrammreihe arbeiten müssen. Beginnen wir mit dem Erstellen einer DataTable für die Products Tabelle.

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

Der Konfigurations-Assistent für TableAdapter beginnt, indem Sie aufgefordert werden, auszuwählen, mit welcher Datenbank sie arbeiten soll. In der Dropdownliste werden diese Datenbanken im Server-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.

Wählen Sie in der Dropdownliste die Northwind-Datenbank aus.

Abbildung 5: Auswählen der Northwind-Datenbank aus der Dropdownliste (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 die Verbindungszeichenfolge in der Web.config Datei speichern möchten. Wenn Sie die Verbindungszeichenfolge speichern, vermeiden Sie, dass sie in den TableAdapter-Klassen hartcodiert wird, was die Dinge vereinfacht, wenn sich die Verbindungszeichenfolge Informationen in Zukunft ändern. Wenn Sie sich dafür entscheiden, die Verbindungszeichenfolge in der Konfigurationsdatei zu speichern, wird sie im <connectionStrings> Abschnitt platziert, der optional für verbesserte Sicherheit verschlüsselt oder später über die neue ASP.NET 2.0-Eigenschaftenseite im IIS-GUI-Verwaltungstool verschlüsselt werden kann, was für Administratoren besser geeignet ist.

Speichern der Verbindungszeichenfolge in Web.config

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

Als Nächstes müssen wir das Schema für die erste stark typierte DataTable definieren und die erste Methode für unser TableAdapter bereitstellen, die beim Auffüllen des stark typierten 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 wir in unserer DataTable widerspiegeln möchten. Am Ende des Assistenten geben wir dieser Abfrage einen Methodennamen. Sobald dies erreicht wurde, kann diese Methode über unsere Präsentationsebene aufgerufen werden. Die Methode führt die definierte Abfrage aus und füllt eine stark typierte DataTable auf.

Um mit der Definition der SQL-Abfrage zu beginnen, müssen wir zunächst angeben, wie das TableAdapter die Abfrage ausgeben soll. Wir können eine Ad-hoc-SQL-Anweisung verwenden, eine neue gespeicherte Prozedur erstellen oder eine vorhandene gespeicherte Prozedur verwenden. Für diese Lernprogramme 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 die Spalten zurückgeben, die in der entsprechenden DataTable ausgedrückt werden müssen. Dazu können wir 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: Eingeben der SQL-Abfrage in das Textfeld (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Verwenden Sie alternativ den Abfrage-Generator, und erstellen Sie die Abfrage grafisch, wie in Abbildung 9 dargestellt.

Grafisches Erstellen der Abfrage über die Abfrage-Editor

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

Klicken Sie nach dem Erstellen der Abfrage, aber bevor Sie auf den nächsten Bildschirm wechseln, auf die Schaltfläche "Erweiterte Optionen". In Websiteprojekten ist "Generierung von Anweisungen zum Einfügen, Aktualisieren und Löschen" standardmäßig die einzige erweiterte Option, die standardmäßig ausgewählt ist. Wenn Sie diesen Assistenten aus einer Klassenbibliothek oder einem Windows-Projekt ausführen, wird auch die Option "Optimistische Parallelität verwenden" ausgewählt. Lassen Sie die Option "Optimistische Parallelität verwenden" vorerst deaktiviert. Wir werden optimistische Parallelität in zukünftigen Lernprogrammen untersuchen.

Wählen Sie nur die Option

Abbildung 10: Auswählen der Option "Einfügen", "Aktualisieren" und "Löschen" (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Klicken Sie nach der Überprüfung der erweiterten Optionen auf "Weiter", um zum endgültigen Bildschirm zu wechseln. Hier werden wir aufgefordert, auszuwählen, welche Methoden dem TableAdapter hinzugefügt werden sollen. Es gibt zwei Muster zum Auffüllen von Daten:

  • Eine DataTable mit diesem Ansatz ausfüllen, wird eine Methode erstellt, die eine DataTable als Parameter verwendet und basierend auf den Ergebnissen der Abfrage auffüllt. Die ADO.NET DataAdapter-Klasse implementiert z. B. dieses Muster mit seiner Fill() Methode.
  • Gibt eine DataTable mit diesem Ansatz zurück, die die Methode erstellt und füllt die DataTable für Sie und gibt sie als Rückgabewert der Methoden zurück.

Sie können das TableAdapter-Objekt mit einem oder beiden Mustern implementieren lassen. Sie können die hier bereitgestellten Methoden auch umbenennen. Lassen Sie beide Kontrollkästchen aktiviert, obwohl wir in diesen Lernprogrammen nur das letztere Muster verwenden. Lassen Sie uns auch die eher generische GetData Methode umbenennen in GetProducts.

Wenn aktiviert, erstellt das letzte Kontrollkästchen "GenerateDBDirectMethods", erstellt Insert(), Update()und Delete() Methoden für "TableAdapter". Wenn Sie diese Option deaktiviert lassen, müssen alle Aktualisierungen über die einzige Update() Methode von TableAdapter erfolgen, die das Typed DataSet, eine DataTable, eine einzelne DataRow oder ein Array von DataRows verwendet. (Wenn Sie die Option "Anweisungen einfügen, aktualisieren und löschen" aus den erweiterten Eigenschaften in Abbildung 9 deaktiviert haben, hat die Einstellung dieses Kontrollkästchens keine Auswirkung.) Lassen Sie dieses Kontrollkästchen aktiviert.

Ändern des Methodennamens von

Abbildung 11: Ändern des Methodennamens in "GetProductsIn GetData " (Klicken, 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, werden wir an den DataSet-Designer zurückgegeben, der die soeben erstellte DataTable anzeigt. Sie können die Liste der Spalten in der Products DataTable (ProductID, ProductNameusw.) sowie die Methoden der ProductsTableAdapter (Fill() und GetProducts()) anzeigen.

Die Products DataTable und ProductsTableAdapter wurden dem typierten DataSet hinzugefügt.

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

An diesem Punkt verfügen wir über ein typiertes DataSet mit einer einzelnen DataTable (Northwind.Products) und einer stark typierten DataAdapter-Klasse (NorthwindTableAdapters.ProductsTableAdapter) mit einer GetProducts() Methode. Diese Objekte können verwendet werden, um auf eine Liste aller Produkte aus 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 von Datenzugriffscode schreiben. Wir mussten keine ADO.NET Klassen instanziieren, wir mussten nicht auf Verbindungszeichenfolge s, SQL-Abfragen oder gespeicherte Prozeduren verweisen. Stattdessen stellt "TableAdapter" den Datenzugriffscode auf niedriger Ebene für uns bereit.

Jedes objekt, das in diesem Beispiel verwendet wird, ist ebenfalls stark typiert, sodass Visual Studio IntelliSense und kompilierte Typüberprüfung bereitstellen kann. Und am besten alle vom TableAdapter zurückgegebenen DataTables können an ASP.NET Datenwebsteuerelemente gebunden werden, z. B. GridView, DetailsView, DropDownList, CheckBoxList und mehrere andere. Im folgenden Beispiel wird veranschaulicht, wie die Von der GetProducts() Methode zurückgegebene DataTable in nur drei Codezeilen innerhalb des Page_Load Ereignishandlers an eine GridView gebunden wird.

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)

Dieses Beispiel erfordert zwar, dass wir drei Codezeilen im Ereignishandler der ASP.NET Seite Page_Load schreiben, in zukünftigen Lernprogrammen wird jedoch untersucht, wie die ObjectDataSource zum deklarativen Abrufen der Daten aus dem DAL verwendet wird. Mit objectDataSource müssen wir keinen Code schreiben und erhalten auch Seiten- und Sortierunterstützung!

Schritt 3: Hinzufügen parametrisierter Methoden zur Datenzugriffsebene

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

Fügen wir die GetProductsByCategoryID(categoryID) Methode hinzu. Wenn Sie dem DAL eine neue Methode hinzufügen möchten, 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

Abbildung 14: Klicken Sie mit der rechten Maustaste auf "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. Lassen Sie uns eine Ad-hoc-SQL-Anweisung erneut verwenden. 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.

Auswählen, ob eine SELECT-Anweisung erstellt werden soll, die Zeilen zurückgibt

Abbildung 15: Auswählen der Erstellung einer SELECT Anweisung, die Zeilen zurückgibt (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Der nächste Schritt besteht darin, die SQL-Abfrage zu definieren, 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 dieselbe SELECT Aussage von GetProducts(), aber fügen Sie die folgende WHERE Klausel hinzu: WHERE CategoryID = @CategoryID Der @CategoryID Parameter gibt dem TableAdapter-Assistenten an, dass für die methode, die wir erstellen, ein Eingabeparameter des entsprechenden Typs erforderlich ist (nämlich eine nullable ganze Zahl).

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

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

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

Auswählen der Namen für die TableAdapter-Methoden

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 der 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 mit der rechten Maustaste auf die Methode im TableAdapter, und wählen Sie "Vorschaudaten" aus. Geben Sie als Nächstes die Werte ein, die für die Parameter verwendet werden sollen, und klicken Sie auf "Vorschau".

Diese Produkte, die zur Kategorie

Abbildung 19: Diese Produkte, die zur Kategorie "Getränke" gehören, werden angezeigt (Zum Anzeigen des Bilds mit voller Größe klicken)

Mit der GetProductsByCategoryID(categoryID) Methode in unserer DAL können wir jetzt eine ASP.NET Seite erstellen, die nur die Produkte in einer bestimmten Kategorie anzeigt. Das folgende Beispiel zeigt alle Produkte, die sich in der Kategorie "Getränke" befinden, die eine CategoryID Von 1 aufweisen.

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

Diese Produkte in der Kategorie Getränke werden angezeigt

Abbildung 20: Diese Produkte in der Kategorie "Getränke" werden angezeigt (Zum Anzeigen des Bilds mit voller Größe klicken)

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 das direkte Datenbankmuster aufrufe, umfasst das Erstellen von Methoden, die beim Aufrufen, Ausgeben eines INSERTOder UPDATEDELETE Befehls für die Datenbank, die für einen einzelnen Datenbankdatensatz ausgeführt wird, erforderlich sind. Solche Methoden werden in der Regel in einer Reihe von skalaren Werten (ganze Zahlen, Zeichenfolgen, Booleans, DateTimes usw.) übergeben, die den Werten entsprechen, die eingefügt, aktualisiert oder gelöscht werden sollen. Bei diesem Muster für die Products Tabelle würde die Delete-Methode z. B. einen ganzzahligen Parameter verwenden, der den ProductID zu löschenden Datensatz angibt, während die Insert-Methode eine Zeichenfolge für die ProductName, eine Dezimalzahl für die UnitPrice, eine ganze Zahl für das UnitsOnStockusw. übernehmen würde.

Jede Anforderung zum Einfügen, Aktualisieren und Löschen wird sofort an die Datenbank gesendet.

Abbildung 21: Jede Anforderung zum Einfügen, Aktualisieren und Löschen wird sofort an die Datenbank gesendet (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Das andere Muster, auf das ich als Batchaktualisierungsmuster verweise, besteht darin, ein gesamtes DataSet, DataTable oder eine Sammlung von DataRows in einem Methodenaufruf zu aktualisieren. Mit diesem Muster löscht, fügt ein Entwickler die DataRows in einer DataTable ein und ändert sie und übergibt diese DataRows oder DataTable dann 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 Update-Methode aufgerufen wird (Klicken Sie, um das Bild in voller Größe anzuzeigen)

The TableAdapter uses the batch update pattern by default, but also supports the DB direct pattern. Da wir beim Erstellen von TableAdapter die Option "Einfügen-, Update- und Delete-Anweisungen generieren" ausgewählt haben, enthält Update() die ProductsTableAdapter Methode eine Methode, die das Batchaktualisierungsmuster implementiert. Insbesondere enthält das TableAdapter eine Update() Methode, die das Typed DataSet, eine stark typierte DataTable oder mindestens ein DataRows übergeben werden kann. Wenn Sie das Kontrollkästchen "GenerateDBDirectMethods" beim ersten Erstellen des TableAdapter aktiviert haben, wird das direkte DB-Muster auch über Insert(), Update()und Delete() Methoden implementiert.

Beide Datenänderungsmuster verwenden die TableAdapter- InsertCommand, UpdateCommand, und DeleteCommand Eigenschaften, um ihre INSERTBefehle UPDATEund DELETE Befehle für die Datenbank ausstellen zu können. Sie können die InsertCommandEigenschaften UpdateCommandund Eigenschaften prüfen und DeleteCommand ändern, indem Sie im DataSet-Designer auf "TableAdapter" klicken und dann zur Eigenschaftenfenster wechseln. (Stellen Sie sicher, dass Sie den TableAdapter ausgewählt haben und dass das ProductsTableAdapter Objekt in der Dropdownliste in der Eigenschaftenfenster ausgewählt ist.)

TableAdapter verfügt über insertCommand-, UpdateCommand- und DeleteCommand-Eigenschaften

Abbildung 23: The TableAdapter has InsertCommand, UpdateCommand, and DeleteCommand Properties (Click to view full-size image)

Wenn Sie eine dieser Datenbankbefehlseigenschaften untersuchen oder ändern möchten, klicken Sie auf die CommandText Untereigenschaft, die den Abfrage-Generator anzeigt.

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

Abbildung 24: Konfigurieren von INSERT, UPDATEund DELETE Anweisungen im Abfrage-Generator (Klicken, um das Bild in voller Größe anzuzeigen)

Das folgende Codebeispiel zeigt, wie Sie das Batchaktualisierungsmuster verwenden, um den Preis aller Produkte zu verdoppeln, die nicht mehr eingestellt sind und 25 Einheiten vorrätig oder weniger aufweisen:

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 eins 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 Methoden zum Einfügen, Aktualisieren und Löschen

Die Insert()von der DIREKTEN DB-Methode erstellten Methoden Update()und Delete() Methoden können ein bisschen umständlich sein, insbesondere für Tabellen mit vielen Spalten. Wenn Sie sich das vorherige Codebeispiel ansehen, ist ohne IntelliSense nicht besonders klar, welche Products Tabellenspalte den einzelnen Eingabeparametern und Insert() Methoden zugeordnet Update() ist. Es kann vorkommen, dass wir nur eine einzelne Spalte oder zwei aktualisieren möchten oder eine angepasste Insert() Methode verwenden möchten, die den Wert des neu eingefügten Datensatzes IDENTITY (automatischer Inkrementierung) 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. Erstellen wir nun eine Methode, die ein neues Produkt hinzufügt und dann den Wert der neu hinzugefügten ProductIDDatensätze zurückgibt. Daher können Sie eine INSERT Abfrage erstellen.

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

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

Auf dem nächsten Bildschirm wird das InsertCommand's 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 wird. (Weitere Informationen SCOPE_IDENTITY() zu und warum Sie wahrscheinlich SCOPE_IDENTITY() anstelle von @@IDENTITY verwenden möchten, finden Sie in der technischen Dokumentation.) Stellen Sie sicher, dass Sie die INSERT Anweisung mit einem Semikolon beenden, bevor Sie die SELECT Anweisung hinzufügen.

Erweitern der Abfrage, um den SCOPE_IDENTITY()-Wert zurückzugeben

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

Benennen Sie schließlich die neue Methode InsertProduct.

Festlegen des Neuen Methodennamens auf InsertProduct

Abbildung 27: Festlegen des Neuen Methodennamens auf InsertProduct (Klicken, um das Bild in voller Größe anzuzeigen)

Wenn Sie zum DataSet-Designer zurückkehren, sehen Sie, dass die ProductsTableAdapter neue Methode enthält. InsertProduct Wenn diese neue Methode keinen Parameter für jede Spalte in der Products Tabelle enthält, 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 Anweisungen SELECT und Anweisungen INSERT begrenzt.

Standardmäßig stellen Methoden keine Abfragemethoden ein, d. h., sie geben die Anzahl der betroffenen Zeilen zurück. Die Methode soll InsertProduct jedoch den von der Abfrage zurückgegebenen Wert zurückgeben, nicht die Anzahl der betroffenen Zeilen. Passen Sie dazu die Eigenschaft der InsertProduct Methode ExecuteMode an Scalar.

Ändern der ExecuteMode-Eigenschaft in Skalar

Abbildung 28: Ändern der ExecuteMode Eigenschaft in Scalar (Klicken, 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 SupplierID aus der Products Tabelle zurückgibt, aber nicht die CategoryName Spalte aus der Categories Tabelle oder spalte CompanyName 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 Werte als auch die CategoryName CompanyName Spaltenwerte einzuschließen, wodurch auch die stark typierte DataTable aktualisiert wird, um diese neuen Spalten einzuschließen.

Dies kann jedoch ein Problem darstellen, da die Methoden des TableAdapters zum Einfügen, Aktualisieren und Löschen von Daten von dieser ursprü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 uns darum kümmern, unsere Abfragen zu Categories und Suppliers als Unterabfragen hinzuzufügen, JOIN vermeiden wir, diese Methoden zum Ändern von Daten neu zu bearbeiten. Klicken Sie mit der rechten Maustaste auf die GetProducts() Methode, 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, 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 enthält zwei neue Spalten.

Abbildung 30: Die Products DataTable verfügt über zwei neue Spalten

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

Wenn Sie die verwendungssyntax GetProducts() SELECT JOIN aktualisieren, kann der DataSet-Designer die Methoden zum Einfügen, Aktualisieren und Löschen von Datenbankdaten nicht mithilfe des direkten DB-Musters automatisch generieren. Stattdessen müssen Sie sie manuell wie bei der InsertProduct Methode weiter oben in diesem Lernprogramm erstellen. Darüber hinaus müssen Sie manuell die Werte für die InsertCommandUpdateCommandBatchaktualisierung und DeleteCommand die Eigenschaft angeben, wenn Sie das Batchaktualisierungsmuster verwenden möchten.

Hinzufügen der verbleibenden TableAdapters

Bisher haben wir nur mit einem einzelnen TableAdapter für eine einzelne Datenbanktabelle gearbeitet. Die Northwind-Datenbank enthält jedoch mehrere verwandte Tabellen, mit denen wir in unserer Webanwendung arbeiten müssen. Ein typiertes 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 Lernprogrammen verwenden. Um einem typierten DataSet ein neues TableAdapter hinzuzufügen, öffnen Sie den DataSet-Designer, klicken Sie mit der rechten Maustaste in den Designer, und wählen Sie "Hinzufügen/TableAdapter" aus. Dadurch wird eine neue DataTable und TableAdapter erstellt und Sie durch den Assistenten geführt, den wir weiter oben in diesem Lernprogramm 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 in den ProductsTableAdapter Unterabfragen enthalten sind, um die Kategorie- und Lieferantennamen der einzelnen Produkte zu erfassen. Wenn Sie weiter folgen, haben Sie außerdem die Klassen GetProducts() und GetProductsByCategoryID(categoryID) Methoden bereits hinzugefügtProductsTableAdapter.

  • 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
      

Der DataSet-Designer nach dem Hinzufügen der vier TableAdapters

Abbildung 31: Der DataSet-Designer nach dem Hinzufügen der vier TableAdapters (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Hinzufügen von benutzerdefiniertem Code zum DAL

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

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

Abbildung 32: Die XML-Schemadefinitionsdatei (XSD) für das vom Typ Northwinds eingegebene DataSet (Klicken Sie, um das Bild mit voller Größe anzuzeigen)

Diese Schemainformationen werden zur Entwurfszeit beim Kompilieren oder zur Laufzeit (falls erforderlich) in C#- oder Visual Basic-Code übersetzt, an dem Sie ihn mit dem Debugger durchlaufen können. 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 Kursansicht 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 anzeigen. 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

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

Während automatisch generierter Code ein großartiger Zeitsparmodus sein kann, ist der Code häufig sehr generisch und muss an die individuellen Anforderungen einer Anwendung angepasst werden. Das Risiko, automatisch generierten Code zu erweitern, besteht jedoch darin, dass das Tool, das den Code generiert hat, entscheiden kann, dass es an der Zeit ist, "neu zu generieren" und Ihre Anpassungen zu überschreiben. Mit dem neuen Teilklassenkonzept von .NET 2.0 ist es einfach, eine Klasse über mehrere Dateien hinweg aufzuteilen. Auf diese Weise können wir unsere eigenen Methoden, Eigenschaften und Ereignisse zu den automatisch generierten Klassen hinzufügen, ohne sich Gedanken über das Überschreiben unserer Anpassungen machen zu müssen.

Um zu veranschaulichen, wie die DAL angepasst wird, 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. Um dies zu erreichen, erstellen Sie eine neue Klassendatei im Ordner mit dem App_Code Namen 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, der beim Erstellen der Klasse die Northwind.SuppliersRow GetProducts() gerade definierte Methode enthält. Wenn Sie Ihr Projekt erstellen und dann zur Klassenansicht zurückkehren, wird GetProducts() sie jetzt als Methode aufgeführt Northwind.SuppliersRow.

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 aufgezählt zu werden, 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 angezeigt werden. Websteuerelemente für NET-Daten. Auf der folgenden Seite wird ein GridView-Steuerelement mit zwei Feldern verwendet:

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

In zukünftigen Lernprogrammen wird untersucht, wie solche Masterdetailberichte angezeigt werden. Dieses Beispiel soll nun die Verwendung der benutzerdefinierten Methode veranschaulichen, 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 wird in der linken Spalte aufgeführt, deren Produkte rechts

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

Zusammenfassung

Beim Erstellen einer Webanwendung, die das DAL erstellt, sollte einer ihrer ersten Schritte sein, bevor Sie mit dem Erstellen der Präsentationsebene beginnen. Mit Visual Studio ist das Erstellen eines DAL basierend auf typierten DataSets eine Aufgabe, die in 10 bis 15 Minuten ohne Schreiben einer Codezeile ausgeführt werden kann. Die Lernprogramme, die in Zukunft vorangehen, bauen auf diesem DAL auf. Im nächsten Lernprogramm definieren wir eine Reihe von Geschäftsregeln und erfahren, wie sie in einer separaten Geschäftslogikebene implementiert werden.

Glückliche Programmierung!

Weitere nützliche Informationen

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

Videoschulung zu Themen, die in diesem Lernprogramm 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 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 über mitchell@4GuysFromRolla.com seinen Blog erreicht werden, der unter .http://ScottOnWriting.NET

Besonderer Dank an

Diese Lernprogrammreihe wurde von vielen hilfreichen Prüfern überprüft. Leitende Prüfer für dieses Lernprogramm waren Ron Green, Hilton Giesenow, Dennis Patterson, Liz Shulok, Abel Gomez und Carlos Santos. Möchten Sie meine bevorstehenden MSDN-Artikel überprüfen? Wenn dies der Fall ist, legen Sie mir eine Zeile bei mitchell@4GuysFromRolla.com.