Freigeben über


Aktualisierung des TableAdapters zur Verwendung von JOINs (C#)

von Scott Mitchell

PDF herunterladen

Beim Arbeiten mit einer Datenbank ist es üblich, Daten anzufordern, die über mehrere Tabellen verteilt sind. Zum Abrufen von Daten aus zwei verschiedenen Tabellen können wir entweder eine korrelierte Unterabfrage oder einen JOIN-Vorgang verwenden. In diesem Lernprogramm vergleichen wir korrelierte Unterabfragen und die JOIN-Syntax, bevor Sie sich ansehen, wie Sie einen TableAdapter erstellen, der eine JOIN in der Hauptabfrage enthält.

Einleitung

Bei relationalen Datenbanken sind die Daten, mit denen wir arbeiten möchten, häufig auf mehrere Tabellen verteilt. Wenn beispielsweise Produktinformationen angezeigt werden, möchten wir wahrscheinlich die entsprechenden Produktkategorien und Lieferantennamen auflisten. Die Products Tabelle enthält CategoryID und SupplierID Werte, aber die tatsächlichen Kategorie- und Lieferantennamen sind jeweils in den Tabellen Categories und Suppliers enthalten.

Um Informationen aus einer anderen verknüpften Tabelle abzurufen, können wir entweder korrelierte Unterabfragen oder JOINs verwenden. Eine korrelierte Unterabfrage ist eine geschachtelte SELECT Abfrage, die auf Spalten in der äußeren Abfrage verweist. Im Lernprogramm zum Erstellen einer Datenzugriffsebene haben wir beispielsweise zwei korrelierte Unterabfragen in der ProductsTableAdapter Hauptabfrage verwendet, um die Kategorie- und Lieferantennamen für jedes Produkt zurückzugeben. A JOIN ist ein SQL-Konstrukt, das verwandte Zeilen aus zwei verschiedenen Tabellen zusammenführt. Wir haben eine JOIN im Lernprogramm zum Abfragen von Daten mit dem SqlDataSource-Steuerelement verwendet, um Kategorieinformationen zusammen mit den einzelnen Produkten anzuzeigen.

Der Grund, warum wir auf die Verwendung von JOIN mit den TableAdapters verzichtet haben, sind die Einschränkungen des TableAdapter-Assistenten bei der automatischen Generierung entsprechender INSERT, UPDATE und DELETE Anweisungen. Wenn die Hauptabfrage des TableAdapters JOINs enthält, kann der TableAdapter die Ad-hoc-SQL-Anweisungen oder gespeicherten Prozeduren für die zugehörigen InsertCommand, UpdateCommand und DeleteCommand-Eigenschaften nicht automatisch erstellen.

In diesem Lernprogramm werden wir kurz korrelierte Unterabfragen und JOINs vergleichen und gegenüberstellen, bevor wir erkunden, wie ein TableAdapter erstellt wird, der JOINs in seiner Hauptabfrage enthält.

Vergleichen und Kontrastieren korrelierter Unterabfragen undJOIN -n

Erinnern Sie sich daran, dass das im ersten Lernprogramm im ProductsTableAdapter DataSet erstellte Northwind korrelierte Unterabfragen verwendet, um die entsprechende Kategorie und den Lieferantennamen jedes Produkts abzurufen. Die ProductsTableAdapter Hauptabfrage wird unten angezeigt.

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

Die beiden korrelierten Unterabfragen - (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) und (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) - sind SELECT-Abfragen, die für jedes Produkt einen einzelnen Wert als zusätzliche Spalte in der Spaltenliste der äußeren SELECT-Anweisung zurückgeben.

Alternativ kann ein JOIN verwendet werden, um den Lieferanten und den Kategorienamen jedes Produkts zurückzugeben. Die folgende Abfrage gibt die gleiche Ausgabe wie die oben genannte abfrage zurück, verwendet JOIN jedoch anstelle von Unterabfragen:

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

Ein JOIN führt Datensätze aus einer Tabelle mit Datensätzen aus einer anderen Tabelle basierend auf bestimmten Kriterien zusammen. In der obigen Abfrage z. B. wird SQL Server angewiesen, jeden Produktdatensatz mit dem Kategoriedatensatz zusammenzuführen, LEFT JOIN Categories ON Categories.CategoryID = Products.CategoryID dessen CategoryID Wert dem Wert des CategoryID Produkts entspricht. Das zusammengeführte Ergebnis ermöglicht es uns, mit den entsprechenden Kategoriefeldern für jedes Produkt zu arbeiten (wie z. B. CategoryName).

Hinweis

JOIN s werden häufig beim Abfragen von Daten aus relationalen Datenbanken verwendet. Wenn Sie neu in der JOIN Syntax sind oder Ihre Kenntnisse auffrischen müssen, würde ich das SQL Join-Lernprogramm bei W3 Schools empfehlen. Lesenswert sind auch die JOIN Abschnitte "Grundlagen " und " Subquery Fundamentals " der SQL-Bücher Online.

Da JOIN s und korrelierte Unterabfragen zum Abrufen verwandter Daten aus anderen Tabellen verwendet werden können, müssen viele Entwickler ihre Köpfe kratzen und sich fragen, welcher Ansatz verwendet werden soll. Alle SQL-Gurus, mit denen ich gesprochen habe, haben ungefähr dasselbe gesagt, dass es nicht wirklich wichtig ist, leistungsmäßig, da SQL Server ungefähr identische Ausführungspläne produzieren wird. Ihre Ratschläge sind dann die Verwendung der Technik, mit der Sie und Ihr Team am besten vertraut sind. Es ist zu beachten, dass diese Experten, nachdem sie diesen Rat gegeben haben, sofort ihre Vorlieben JOIN gegenüber korrelierten Unterabfragen ausdrücken.

Beim Erstellen einer Datenzugriffsebene mit typierten DataSets funktionieren die Tools besser bei der Verwendung von Unterabfragen. Insbesondere generiert der TableAdapter-Assistent keine entsprechenden INSERT, UPDATE, und DELETE-Anweisungen automatisch, wenn die Hauptabfrage JOIN-s enthält, generiert diese Anweisungen jedoch automatisch, wenn korrelierte Unterabfragen verwendet werden.

Um diesen Mangel zu untersuchen, erstellen Sie ein temporäres Typed DataSet im Ordner ~/App_Code/DAL. Wählen Sie während des TableAdapter-Konfigurations-Assistenten die Verwendung von AD-hoc-SQL-Anweisungen aus, und geben Sie die folgende SELECT Abfrage ein (siehe Abbildung 1):

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

Screenshot des Fensters

Abbildung 1: Eingeben einer Hauptabfrage, die 's' enthält JOIN (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Standardmäßig erstellt der TableAdapter automatisch INSERT, UPDATE und DELETE Anweisungen basierend auf der Hauptabfrage. Wenn Sie auf die Schaltfläche "Erweitert" klicken, können Sie sehen, dass dieses Feature aktiviert ist. Trotz dieser Einstellung kann der TableAdapter die INSERT, UPDATE und DELETE Anweisungen nicht erstellen, da die Hauptabfrage eine JOIN enthält.

Screenshot des Fensters

Abbildung 2: Eingeben einer Hauptabfrage, die s enthält JOIN

Klicken Sie auf Fertig stellen, um den Assistenten abzuschließen. An diesem Punkt enthält der DataSet-Designer einen einzelnen TableAdapter mit einer DataTable, die Spalten für jedes der Felder umfasst, die in der Spaltenliste der Abfrage SELECT zurückgegeben werden. Dies schließt die CategoryName und SupplierName, wie Abbildung 3 zeigt, ein.

Die DataTable enthält eine Spalte für jedes Feld, das in der Spaltenliste zurückgegeben wird.

Abbildung 3: Die DataTable enthält eine Spalte für jedes Feld, das in der Spaltenliste zurückgegeben wird.

Während die DataTable über die entsprechenden Spalten verfügt, fehlen dem TableAdapter die Werte für seine InsertCommand, UpdateCommand und DeleteCommand Eigenschaften. Um dies zu bestätigen, klicken Sie im Designer auf den TableAdapter, und wechseln Sie dann zum Eigenschaftenfenster. Dort sehen Sie, dass die InsertCommand, UpdateCommand und DeleteCommand Eigenschaften, auf (Keine) festgelegt sind.

Die Eigenschaften InsertCommand, UpdateCommand und DeleteCommand sind auf (Keine) festgelegt.

Abbildung 4: Die InsertCommandUnd UpdateCommandDeleteCommand Eigenschaften sind auf (Keine) festgelegt (Klicken, um das Bild in voller Größe anzuzeigen)

Um dieses Manko zu umgehen, können wir die SQL-Anweisungen und Parameter für die Eigenschaften InsertCommand, UpdateCommand und DeleteCommand über das Eigenschaftenfenster manuell bereitstellen. Alternativ können wir mit der Konfiguration der TableAdapter-Hauptabfrage beginnen, um keineJOIN s einzuschließen. Dadurch können die INSERT, UPDATE und DELETE Anweisungen automatisch generiert werden. Nach Abschluss des Assistenten konnten wir den TableAdapter SelectCommand dann manuell aus dem Eigenschaftenfenster aktualisieren, sodass er die JOIN Syntax enthält.

Während dieser Ansatz funktioniert, ist er sehr anfällig, wenn Ad-hoc-SQL-Abfragen verwendet werden, da jedes Mal, wenn die Hauptabfrage des TableAdapters über den Assistenten neu konfiguriert wird, die automatisch generierten INSERT, UPDATE, und DELETE Anweisungen neu erstellt werden. Dies bedeutet, dass alle später vorgenommenen Anpassungen verloren gehen würden, wenn wir mit der rechten Maustaste auf das TableAdapter-Objekt geklickt haben, im Kontextmenü "Konfigurieren" ausgewählt und den Assistenten erneut abgeschlossen haben.

Die Sprödigkeit der automatisch generierten INSERT, UPDATE, und DELETE-Anweisungen des TableAdapters ist glücklicherweise auf Ad-hoc-SQL-Anweisungen beschränkt. Wenn Ihr TableAdapter gespeicherte Prozeduren verwendet, können Sie die gespeicherten Prozeduren SelectCommand, InsertCommand, UpdateCommand oder DeleteCommand anpassen und den Assistenten für die TableAdapter-Konfiguration erneut ausführen, ohne befürchten zu müssen, dass die gespeicherten Prozeduren geändert werden.

Über die nächsten Schritte werden wir einen TableAdapter erstellen, der zunächst eine Hauptabfrage verwendet, die alle JOIN-Elemente auslässt, sodass die entsprechenden gespeicherten Prozeduren zum Einfügen, Aktualisieren und Löschen automatisch generiert werden. Anschließend aktualisieren wir das SelectCommand, damit ein JOIN verwendet wird, das zusätzliche Spalten aus verknüpften Tabellen zurückgibt. Schließlich erstellen wir eine entsprechende Business Logic Layer-Klasse und veranschaulichen die Verwendung des TableAdapter in einer ASP.NET Webseite.

Schritt 1: Erstellen des TableAdapters mithilfe einer vereinfachten Hauptabfrage

In diesem Tutorial fügen wir eine TableAdapter und eine stark typisierte DataTable für die Employees-Tabelle im NorthwindWithSprocs-DataSet hinzu. Die Employees Tabelle enthält ein ReportsTo Feld, das den EmployeeID Vorgesetzten des Mitarbeiters angegeben hat. Beispielsweise hat die Mitarbeiterin Anne Dodsworth den ReportTo Wert 5, welcher identisch mit dem EmployeeID von Steven Buchanan ist. Folglich berichtet Anne an Steven, ihren Vorgesetzten. Zusammen mit der Berichterstattung über den Wert jedes Mitarbeiters ReportsTo möchten wir möglicherweise auch den Namen deren Vorgesetzten abrufen. Dies kann mithilfe einer JOIN. Die Verwendung einer JOIN beim Erstellen des TableAdapters verhindert jedoch, dass der Assistent automatisch die entsprechenden Einfüge-, Update- und Löschmöglichkeiten generiert. Daher erstellen wir zunächst einen TableAdapter, dessen Hauptabfrage keine JOIN enthält. Dann aktualisieren wir in Schritt 2 die gespeicherte Prozedur der Hauptabfrage, um den Namen des Vorgesetzten über eine JOIN abzurufen.

Öffnen Sie zunächst das NorthwindWithSprocs DataSet im ~/App_Code/DAL Ordner. Klicken Sie mit der rechten Maustaste auf den Designer, wählen Sie die Option "Hinzufügen" aus dem Kontextmenü aus, und wählen Sie das Menüelement "TableAdapter" aus. Dadurch wird der Konfigurations-Assistent "TableAdapter" gestartet. Wie in Abbildung 5 dargestellt, lassen Sie den Assistenten neue gespeicherte Prozeduren erstellen und klicken Sie auf "Weiter". Zur Auffrischung, wie man neue gespeicherte Prozeduren mit dem TableAdapter-Assistenten erstellt, konsultieren Sie das Tutorial Erstellen neuer gespeicherter Prozeduren für die TableAdapters des Typed DataSets.

Wählen Sie die Option

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

Verwenden Sie die folgende SELECT Anweisung für die TableAdapter-Hauptabfrage:

SELECT EmployeeID, LastName, FirstName, Title, HireDate, ReportsTo, Country
FROM Employees

Da diese Abfrage keine JOIN-Elemente enthält, erstellt der TableAdapter-Assistent automatisch gespeicherte Prozeduren mit entsprechenden INSERT, UPDATE, und DELETE-Anweisungen sowie eine gespeicherte Prozedur zum Ausführen der Hauptabfrage.

Im folgenden Schritt können wir die gespeicherten Prozeduren von TableAdapter benennen. Verwenden Sie die Namen Employees_Select, Employees_Insert, Employees_Updateund Employees_Delete, wie in Abbildung 6 dargestellt.

Benennen der gespeicherten Prozeduren von TableAdapter

Abbildung 6: Benennen der gespeicherten Prozeduren von TableAdapter (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Im letzten Schritt werden wir aufgefordert, die TableAdapter-Methoden zu benennen. Verwenden Fill Und GetEmployees als Methodennamen. Achten Sie außerdem darauf, dass die Methoden "Erstellen" aktiviert bleiben, um Aktualisierungen direkt an die Datenbank (GenerateDBDirectMethods) zu senden.

Benennen der TableAdapter-Methoden Fill und GetEmployees

Abbildung 7: Benennen der TableAdapter-Methoden Fill und GetEmployees (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Nach Abschluss des Assistenten nehmen Sie sich einen Moment Zeit, um die gespeicherten Prozeduren in der Datenbank zu überprüfen. Sie sollten vier neue sehen: Employees_Select, , Employees_Insert, Employees_Updateund Employees_Delete. Überprüfen Sie als Nächstes die soeben erstellten EmployeesDataTable und EmployeesTableAdapter. Die DataTable enthält eine Spalte für jedes Feld, das von der Hauptabfrage zurückgegeben wird. Klicken Sie auf "TableAdapter", und wechseln Sie dann zum Fenster "Eigenschaften". Dort sehen Sie, dass die InsertCommandEigenschaften UpdateCommandund Eigenschaften DeleteCommand ordnungsgemäß konfiguriert sind, um die entsprechenden gespeicherten Prozeduren aufzurufen.

Das TableAdapter umfasst Einfüge-, Aktualisierungs- und Löschfunktionen

Abbildung 8: Das TableAdapter-Element enthält Die Funktionen "Einfügen", "Aktualisieren" und "Löschen" (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Mit den automatisch erstellten gespeicherten Prozeduren zum Einfügen, Aktualisieren und Löschen sowie der InsertCommand, UpdateCommand, DeleteCommand ordnungsgemäß konfigurierten Eigenschaften können wir die gespeicherte Prozedur SelectCommand anpassen, um zusätzliche Informationen über den Vorgesetzten jedes Mitarbeiters zurückzugeben. Insbesondere müssen wir die Employees_Select gespeicherte Prozedur aktualisieren, um einen JOIN zu verwenden und die Werte FirstName und LastName des Managers zurückzugeben. Nachdem die gespeicherte Prozedur aktualisiert wurde, müssen wir die DataTable aktualisieren, damit sie diese zusätzlichen Spalten enthält. Diese beiden Aufgaben werden in schritt 2 und 3 behandelt.

Schritt 2: Anpassen der gespeicherten Prozedur zum Einschließen einerJOIN

Beginnen Sie, indem Sie zum Server-Explorer wechseln, einen Drilldown in den Ordner "Gespeicherte Prozeduren der Northwind-Datenbank" ausführen und die Employees_Select gespeicherte Prozedur öffnen. Wenn diese gespeicherte Prozedur nicht angezeigt wird, klicken Sie mit der rechten Maustaste auf den Ordner "Gespeicherte Prozeduren", und wählen Sie "Aktualisieren" aus. Aktualisieren Sie die gespeicherte Prozedur, sodass ein LEFT JOIN den Vor- und Nachnamen des Managers zurückgibt.

SELECT Employees.EmployeeID, Employees.LastName, 
       Employees.FirstName, Employees.Title, 
       Employees.HireDate, Employees.ReportsTo, 
       Employees.Country,
       Manager.FirstName as ManagerFirstName, 
       Manager.LastName as ManagerLastName
FROM Employees
    LEFT JOIN Employees AS Manager ON
        Employees.ReportsTo = Manager.EmployeeID

Nachdem Sie die SELECT Anweisung aktualisiert haben, speichern Sie die Änderungen, indem Sie zum Menü "Datei" wechseln und "Speichern" Employees_Selectauswählen. Alternativ können Sie auf das Symbol "Speichern" auf der Symbolleiste klicken oder STRG+S drücken. Klicken Sie nach dem Speichern der Änderungen mit der rechten Maustaste auf die Employees_Select gespeicherte Prozedur im Server-Explorer, und wählen Sie "Ausführen" aus. Dadurch wird die gespeicherte Prozedur ausgeführt und die Ergebnisse im Ausgabefenster angezeigt (siehe Abbildung 9).

Die Ergebnisse gespeicherter Prozeduren werden im Ausgabefenster angezeigt.

Abbildung 9: Die Ergebnisse gespeicherter Prozeduren werden im Ausgabefenster angezeigt (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Schritt 3: Aktualisieren der Datentabellenspalten

Zu diesem Zeitpunkt gibt die gespeicherte Prozedur Employees_Select und ManagerFirstName Werte zurück, aber der ManagerLastName fehlen diese Spalten. Diese fehlenden Spalten können der DataTable auf zwei Arten hinzugefügt werden:

  • Manuell – klicken Sie mit der rechten Maustaste auf die DataTable im DataSet-Designer, und wählen Sie im Menü "Hinzufügen" die Option "Spalte" aus. Anschließend können Sie die Spalte benennen und deren Eigenschaften entsprechend festlegen.
  • Automatisch – der TableAdapter-Konfigurations-Assistent aktualisiert die Datentabellenspalten so, dass sie die von der SelectCommand gespeicherten Prozedur zurückgegebenen Felder widerspiegeln. Wenn Sie Ad-hoc-SQL-Anweisungen verwenden, entfernt der Assistent auch die InsertCommand, UpdateCommand und DeleteCommand Eigenschaften, da SelectCommand jetzt JOIN enthält. Wenn Sie gespeicherte Prozeduren verwenden, bleiben diese Befehlseigenschaften jedoch erhalten.

Wir haben das manuelle Hinzufügen von DataTable-Spalten in früheren Tutorials untersucht, einschließlich Master/Detail mit einer Aufzählungsliste von Master-Datensätzen mit einer Detail-DataList und Dateien hochladen, und wir werden diesen Prozess in unserem nächsten Tutorial erneut ausführlicher betrachten. In diesem Tutorial verwenden wir jedoch den automatischen Ansatz über den TableAdapter-Konfigurationsassistenten.

Klicken Sie zunächst mit der rechten Maustaste auf das EmployeesTableAdapter Kontextmenü, und wählen Sie "Konfigurieren" aus. Dadurch wird der TableAdapter-Konfigurations-Assistent angezeigt, der die gespeicherten Prozeduren auflistet, die zum Auswählen, Einfügen, Aktualisieren und Löschen sowie deren Rückgabewerte und Parameter (falls vorhanden) verwendet werden. Abbildung 10 zeigt diesen Assistenten. Hier sehen wir, dass die gespeicherte Prozedur Employees_Select jetzt die Felder ManagerFirstName und ManagerLastName zurückgibt.

Der Assistent zeigt die aktualisierte Spaltenliste für die Employees_Select gespeicherte Prozedur an.

Abbildung 10: Der Assistent zeigt die aktualisierte Spaltenliste für die Employees_Select gespeicherte Prozedur an (Klicken, um das Bild in voller Größe anzuzeigen)

Schließen Sie den Assistenten ab, indem Sie auf "Fertig stellen" klicken. Wenn Sie zum DataSet-Designer zurückkehren, enthält dies EmployeesDataTable zwei zusätzliche Spalten: ManagerFirstName und ManagerLastName.

Die EmployeesDataTable enthält zwei neue Spalten.

Abbildung 11: Enthält EmployeesDataTable zwei neue Spalten (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Um zu veranschaulichen, dass die aktualisierte Employees_Select gespeicherte Prozedur wirksam ist und dass die Einfüge-, Aktualisierungs- und Löschfunktionen des TableAdapter-Elements weiterhin funktionsfähig sind, erstellen wir eine Webseite, auf der Benutzer Mitarbeiter anzeigen und löschen können. Bevor wir eine solche Seite erstellen, müssen wir jedoch zuerst eine neue Klasse in der Business Logic Layer erstellen, um mit Mitarbeitern aus dem NorthwindWithSprocs DataSet zu arbeiten. In Schritt 4 erstellen wir eine EmployeesBLLWithSprocs Klasse. In Schritt 5 verwenden wir diese Klasse von einer ASP.NET Seite.

Schritt 4: Implementieren der Geschäftslogikebene

Erstellen Sie eine neue Klassendatei im Ordner mit dem ~/App_Code/BLL Namen EmployeesBLLWithSprocs.cs. Diese Klasse imitiert die Semantik der vorhandenen EmployeesBLL Klasse, nur diese neue Klasse bietet weniger Methoden und verwendet dataSet NorthwindWithSprocs (anstelle des Northwind DataSet). Fügen Sie der klasse EmployeesBLLWithSprocs den folgenden Code hinzu.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindWithSprocsTableAdapters;
[System.ComponentModel.DataObject]
public class EmployeesBLLWithSprocs
{
    private EmployeesTableAdapter _employeesAdapter = null;
    protected EmployeesTableAdapter Adapter
    {
        get
        {
            if (_employeesAdapter == null)
                _employeesAdapter = new EmployeesTableAdapter();
            return _employeesAdapter;
        }
    }
    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, true)]
    public NorthwindWithSprocs.EmployeesDataTable GetEmployees()
    {
        return Adapter.GetEmployees();
    }
    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Delete, true)]
    public bool DeleteEmployee(int employeeID)
    {
        int rowsAffected = Adapter.Delete(employeeID);
        // Return true if precisely one row was deleted, otherwise false
        return rowsAffected == 1;
    }
}

Die EmployeesBLLWithSprocs Klasse s-Eigenschaft Adapter gibt eine Instanz der NorthwindWithSprocs DataSet s EmployeesTableAdapterzurück. Dies wird von der Klasse s GetEmployees und den Methoden DeleteEmployee verwendet. Die GetEmployees Methode ruft die entsprechende EmployeesTableAdapterGetEmployees Methode auf, die die gespeicherte Employees_Select Prozedur aufruft und die Ergebnisse in einer EmployeeDataTable ausgibt. Die DeleteEmployee Methode ruft auf ähnliche Weise die EmployeesTableAdapter s-Methode Delete auf, die die Employees_Delete gespeicherte Prozedur aufruft.

Schritt 5: Arbeiten mit den Daten in der Präsentationsebene

Nachdem der EmployeesBLLWithSprocs Kurs abgeschlossen ist, können wir über eine ASP.NET Seite mit Mitarbeiterdaten zusammenarbeiten. Öffnen Sie die JOINs.aspx-Seite im AdvancedDAL-Ordner; ziehen Sie ein GridView aus der Toolbox auf den Designer und legen Sie dessen ID-Eigenschaft auf Employees fest. Binden Sie als Nächstes aus dem Smarttag von GridView das Raster an ein neues ObjectDataSource-Steuerelement mit dem Namen EmployeesDataSource.

Konfigurieren Sie die ObjectDataSource so, dass sie die EmployeesBLLWithSprocs Klasse verwendet. Stellen Sie sicher, dass die GetEmployees und DeleteEmployee Methoden in den Dropdownlisten der Registerkarten SELECT und DELETE ausgewählt werden. Klicken Sie auf "Fertig stellen", um die ObjectDataSource-Konfiguration abzuschließen.

Konfigurieren Sie die ObjectDataSource zur Verwendung der EmployeesBLLWithSprocs-Klasse

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

Verwenden Sie die ObjectDataSource, um die Methoden

Abbildung 13: Verwenden der ObjectDataSource-Methode (GetEmployeesDeleteEmployeeKlicken Sie, um das Bild in voller Größe anzuzeigen)

Visual Studio fügt der GridView für jede der EmployeesDataTable Spalten ein BoundField hinzu. Entfernen Sie alle diese BoundFields mit Ausnahme von Title, LastName, FirstName, ManagerFirstName und ManagerLastName und benennen Sie die HeaderText-Eigenschaften der letzten vier BoundFields in Nachname, Vorname, Vorname des Vorgesetzten und Nachname des Vorgesetzten um.

Damit Benutzer Mitarbeiter von dieser Seite löschen können, müssen wir zwei Dinge ausführen. Weisen Sie zunächst die GridView an, Löschfunktionen bereitzustellen, indem Sie die Option "Löschen aktivieren" aus ihrem Smarttag überprüfen. Ändern Sie zweitens die ObjectDataSource-Eigenschaft OldValuesParameterFormatString von dem vom ObjectDataSource-Assistenten (original_{0}) festgelegten Wert in den Standardwert ({0}). Nachdem Sie diese Änderungen vorgenommen haben, sollte ihr deklaratives GridView- und ObjectDataSource-Markup ähnlich wie folgt aussehen:

<asp:GridView ID="Employees" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="EmployeeID" DataSourceID="EmployeesDataSource">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        <asp:BoundField DataField="Title" 
            HeaderText="Title" 
            SortExpression="Title" />
        <asp:BoundField DataField="LastName" 
            HeaderText="Last Name" 
            SortExpression="LastName" />
        <asp:BoundField DataField="FirstName" 
            HeaderText="First Name" 
            SortExpression="FirstName" />
        <asp:BoundField DataField="ManagerFirstName" 
            HeaderText="Manager's First Name" 
            SortExpression="ManagerFirstName" />
        <asp:BoundField DataField="ManagerLastName" 
            HeaderText="Manager's Last Name" 
            SortExpression="ManagerLastName" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="EmployeesDataSource" runat="server" 
    DeleteMethod="DeleteEmployee" OldValuesParameterFormatString="{0}" 
    SelectMethod="GetEmployees" TypeName="EmployeesBLLWithSprocs">
    <DeleteParameters>
        <asp:Parameter Name="employeeID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

Testen Sie die Seite, indem Sie sie über einen Browser besuchen. Wie in Abbildung 14 dargestellt, listet die Seite jeden Mitarbeiter und seinen Vorgesetztennamen auf (vorausgesetzt, sie haben einen).

Der JOIN in der gespeicherten Prozedur Employees_Select gibt den Namen des Managers zurück

Abbildung 14: Die JOIN in der Employees_Select gespeicherten Prozedur gibt den Namen des Managers zurück (Klicken Sie, um das Bild in voller Größe anzuzeigen)

Durch Klicken auf die Schaltfläche "Löschen" wird der Löschworkflow gestartet, der zur Ausführung der Employees_Delete gespeicherten Prozedur führt. Die versuchte Anweisung in der gespeicherten DELETE Prozedur schlägt jedoch aufgrund einer Verletzung der Fremdschlüsseleinschränkung fehl (siehe Abbildung 15). Insbesondere verfügt jeder Mitarbeiter über einen oder mehrere Datensätze in der Orders Tabelle, wodurch der Löschvorgang fehlschlägt.

Das Löschen von Mitarbeitern mit entsprechenden Aufträgen führt zu einer Verletzung der Fremdschlüsseleinschränkung

Abbildung 15: Wenn ein Mitarbeiter gelöscht wird, der mit entsprechenden Bestellungen verknüpft ist, führt dies zu einer Verletzung der Fremdschlüsseleinschränkung (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Damit ein Mitarbeiter gelöscht werden kann, können Sie folgende Aktionen ausführen:

  • Aktualisieren Sie die Fremdschlüsseleinschränkung, um Löschvorgänge zu übernehmen.
  • Löschen Sie die Datensätze manuell aus der Orders Tabelle für die Mitarbeiter, die Sie löschen möchten, oder
  • Aktualisieren Sie die Employees_Delete gespeicherte Prozedur, um zuerst die zugehörigen Datensätze aus der Orders Tabelle zu löschen, bevor Sie den Employees Datensatz löschen. Wir haben diese Technik im Tutorial "Verwendung bestehender gespeicherter Prozeduren für TableAdapters in typisierten DataSets" diskutiert.

Ich lasse dies als Übung für den Leser.

Zusammenfassung

Beim Arbeiten mit relationalen Datenbanken ist es üblich, dass Abfragen ihre Daten aus mehreren verknüpften Tabellen abrufen. Korrelierte Unterabfragen und JOIN -abfragen bieten zwei verschiedene Techniken für den Zugriff auf Daten aus verknüpften Tabellen in einer Abfrage. In früheren Lernprogrammen haben wir am häufigsten korrelierte Unterabfragen verwendet, da der TableAdapter keine INSERT-, UPDATE- und DELETE-Anweisungen für Abfragen, die JOIN betreffen, automatisch generieren kann. Während diese Werte manuell eingegeben werden können, werden bei Verwendung von Ad-hoc-SQL-Anweisungen alle Anpassungen überschrieben, wenn der TableAdapter-Konfigurationsassistent abgeschlossen ist.

Glücklicherweise leiden TableAdapters, die mit gespeicherten Prozeduren erstellt wurden, nicht unter der gleichen Sprödigkeit wie diejenigen, die mit Ad-hoc-SQL-Anweisungen erstellt wurden. Daher ist es möglich, ein TableAdapter-Objekt zu erstellen, dessen Hauptabfrage ein JOIN bei Verwendung von gespeicherten Prozeduren benutzt. In diesem Tutorial sahen wir, wie so ein TableAdapter erstellt wird. Wir haben mit der Verwendung einer JOIN-less-Abfrage SELECT für die TableAdapter-Hauptabfrage begonnen, damit die entsprechenden gespeicherten Prozeduren zum Einfügen, Aktualisieren und Löschen automatisch erstellt werden. Nachdem die anfängliche Konfiguration des TableAdapter abgeschlossen war, haben wir die gespeicherte Prozedur SelectCommand erweitert, um ein JOIN zu nutzen, und den TableAdapter-Konfigurations-Assistenten erneut ausgeführt, um die Spalten von EmployeesDataTable zu aktualisieren.

Beim erneuten Ausführen des TableAdapter-Konfigurations-Assistenten wurden die EmployeesDataTable Spalten automatisch aktualisiert, um die von der Employees_Select gespeicherten Prozedur zurückgegebenen Datenfelder wiederzugeben. Alternativ könnten wir diese Spalten manuell zur DataTable hinzugefügt haben. Im nächsten Lernprogramm werden wir das manuelle Hinzufügen von Spalten zur DataTable untersuchen.

Glückliche Programmierung!

Zum Autor

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

Besonderer Dank an

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