Erstellen einer Datenzugriffsschicht (VB)
von Scott Mitchell
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.
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_Data
Ordner
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.
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
, , UPDATE
und 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ückgibtGetProductsByCategoryID(categoryID)
, die alle Produkte zurückgibt, die zu einer bestimmten Kategorie gehörenGetProductByProductID(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.
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
.
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.
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.
Abbildung 6: Speichern der Verbindungszeichenfolge (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 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.
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:
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.
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.
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.
Abbildung 11: Ändern des Methodennamens in "GetProducts
In 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
, ProductName
usw.) sowie die Methoden der ProductsTableAdapter
(Fill()
und GetProducts()
) anzeigen.
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
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.
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.
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).
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
.
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.
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".
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
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 INSERT
Oder UPDATE
DELETE
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 UnitsOnStock
usw. übernehmen würde.
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.
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 INSERT
Befehle UPDATE
und DELETE
Befehle für die Datenbank ausstellen zu können. Sie können die InsertCommand
Eigenschaften UpdateCommand
und 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.)
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.
Abbildung 24: Konfigurieren von INSERT
, UPDATE
und 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 ProductID
Datensätze zurückgibt. Daher können Sie eine INSERT
Abfrage erstellen.
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.
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
.
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
.
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
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
.
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 InsertCommand
UpdateCommand
Batchaktualisierung 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
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.
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.
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
.
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
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:
- Erstellen eines DAL mit stark typierten TableAdapters und DataTables in VS 2005 und ASP.NET 2.0
- Entwerfen von Datenebenenkomponenten und Übergeben von Daten über Ebenen
- Verschlüsseln von Konfigurationsinformationen in ASP.NET 2.0-Anwendungen
- Übersicht über TableAdapters
- Arbeiten mit einem typierten DataSet
- Verwenden des stark typierten Datenzugriffs in Visual Studio 2005 und ASP.NET 2.0
- So erweitern Sie TableAdapter-Methoden
Videoschulung zu Themen, die in diesem Lernprogramm enthalten sind
- Datenzugriffsschichten in ASP.NET-Anwendungen
- Manuelles Binden eines Datasets an ein Datagrid
- So arbeiten Sie mit Datasets und Filtern aus einer ASP-Anwendung
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.