Share via


Verwenden von Entity Framework 4.0 und dem ObjectDataSource-Steuerelement, Teil 1: Erste Schritte

von Tom Dykstra

Diese Tutorialreihe baut auf der Webanwendung der Contoso University auf, die vom Erste Schritte mit der Tutorialreihe Entity Framework 4.0 erstellt wird. Wenn Sie die vorherigen Tutorials nicht abgeschlossen haben, können Sie als Ausgangspunkt für dieses Tutorial die Anwendung herunterladen, die Sie erstellt hätten. Sie können auch die Anwendung herunterladen, die von der vollständigen Tutorialreihe erstellt wird.

Die Beispielwebanwendung der Contoso University veranschaulicht das Erstellen ASP.NET Web Forms Anwendungen mit Entity Framework 4.0 und Visual Studio 2010. Die Beispielanwendung ist eine Website für eine fiktive Contoso University. Sie enthält Funktionen wie die Zulassung von Studenten, die Erstellung von Kursen und Aufgaben von Dozenten.

Das Tutorial zeigt Beispiele in C#. Das herunterladbare Beispiel enthält Code in C# und Visual Basic.

Database First

Es gibt drei Möglichkeiten, mit Daten im Entity Framework zu arbeiten: Database First, Model First und Code First. Dieses Tutorial gilt für Database First. Informationen zu den Unterschieden zwischen diesen Workflows und Anleitungen zur Auswahl des besten Workflows für Ihr Szenario finden Sie unter Entity Framework-Entwicklungsworkflows.

Web Forms

Wie die Erste Schritte-Serie verwendet diese Tutorialreihe das ASP.NET Web Forms-Modell und setzt voraus, dass Sie wissen, wie Sie mit ASP.NET Web Forms in Visual Studio arbeiten. Falls nicht, lesen Sie Erste Schritte mit ASP.NET 4.5 Web Forms. Wenn Sie lieber mit dem ASP.NET MVC-Framework arbeiten möchten, lesen Sie Erste Schritte mit dem Entity Framework mithilfe ASP.NET MVC.

Softwareversionen

Im Tutorial gezeigt Funktioniert auch mit
Windows 7 Windows 8
Visual Studio 2010 Visual Studio 2010 Express für Web. Das Tutorial wurde nicht mit höheren Versionen von Visual Studio getestet. Es gibt viele Unterschiede bei der Menüauswahl, dialogfeldern und Vorlagen.
.NET 4 .NET 4.5 ist abwärtskompatibel mit .NET 4, aber das Tutorial wurde nicht mit .NET 4.5 getestet.
Entity Framework 4 Das Tutorial wurde nicht mit höheren Versionen von Entity Framework getestet. Ab Entity Framework 5 verwendet EF standardmäßig das, das DbContext API mit EF 4.1 eingeführt wurde. Das EntityDataSource-Steuerelement wurde für die Verwendung der ObjectContext API entwickelt. Informationen zur Verwendung des EntityDataSource-Steuerelements mit der DbContext API finden Sie in diesem Blogbeitrag.

Fragen

Wenn Sie Fragen haben, die sich nicht direkt auf das Tutorial beziehen, können Sie diese im ASP.NET Entity Framework-Forum, im Entity Framework- und LINQ to Entities-Forum oder StackOverflow.com veröffentlichen.

Das EntityDataSource Steuerelement ermöglicht es Ihnen, eine Anwendung sehr schnell zu erstellen, erfordert jedoch in der Regel, dass Sie eine erhebliche Menge an Geschäftslogik und Datenzugriffslogik auf Ihren ASPX-Seiten aufbewahren. Wenn Sie erwarten, dass Ihre Anwendung an Komplexität wächst und eine fortlaufende Wartung erforderlich ist, können Sie im Voraus mehr Entwicklungszeit investieren, um eine n-Schicht - oder mehrschichtige Anwendungsstruktur zu erstellen, die verwaltbarer ist. Um diese Architektur zu implementieren, trennen Sie die Präsentationsebene von der Geschäftslogikebene (Business Logic Layer, BLL) und der Datenzugriffsebene (Data Access Layer, DAL). Eine Möglichkeit, diese Struktur zu implementieren, besteht darin, das ObjectDataSource -Steuerelement anstelle des -Steuerelements EntityDataSource zu verwenden. Wenn Sie das ObjectDataSource Steuerelement verwenden, implementieren Sie Ihren eigenen Datenzugriffscode und rufen es dann auf ASPX-Seiten auf, indem Sie ein Steuerelement verwenden, das viele der gleichen Features wie andere Datenquellensteuerelemente aufweist. Auf diese Weise können Sie die Vorteile eines n-Ebenen-Ansatzes mit den Vorteilen der Verwendung eines Web Forms-Steuerelements für den Datenzugriff kombinieren.

Die ObjectDataSource Steuerung bietet Ihnen auch auf andere Weise mehr Flexibilität. Da Sie Ihren eigenen Datenzugriffscode schreiben, ist es einfacher, mehr zu tun, als nur einen bestimmten Entitätstyp zu lesen, einzufügen, zu aktualisieren oder zu löschen. Dies sind die Aufgaben, für die das EntityDataSource Steuerelement konzipiert ist. Beispielsweise können Sie bei jeder Aktualisierung einer Entität Eine Protokollierung durchführen, Daten archivieren, wenn eine Entität gelöscht wird, oder beim Einfügen einer Zeile mit einem Fremdschlüsselwert die entsprechenden Daten automatisch überprüfen und aktualisieren.

Geschäftslogik- und Repositoryklassen

Ein ObjectDataSource Steuerelement funktioniert durch Aufrufen einer klasse, die Sie erstellen. Die -Klasse enthält Methoden zum Abrufen und Aktualisieren von Daten, und Sie geben die Namen dieser Methoden für das ObjectDataSource Steuerelement im Markup an. Ruft während der Rendering- oder Postbackverarbeitung die ObjectDataSource von Ihnen angegebenen Methoden auf.

Neben grundlegenden CRUD-Vorgängen muss die Klasse, die Sie für die Verwendung mit dem ObjectDataSource Steuerelement erstellen, möglicherweise Geschäftslogik ausführen, wenn daten ObjectDataSource gelesen oder aktualisiert werden. Wenn Sie beispielsweise eine Abteilung aktualisieren, müssen Sie möglicherweise überprüfen, ob keine anderen Abteilungen über denselben Administrator verfügen, da eine Person nicht Administrator von mehr als einer Abteilung sein kann.

In einigen ObjectDataSource Dokumentationen, z. B. der Übersicht über die ObjectDataSource-Klasse, ruft das Steuerelement eine Klasse auf, die als Geschäftsobjekt bezeichnet wird und sowohl Geschäftslogik als auch Datenzugriffslogik enthält. In diesem Tutorial erstellen Sie separate Klassen für Geschäftslogik und Datenzugriffslogik. Die Klasse, die datenzugriffslogik kapselt, wird als Repository bezeichnet. Die Geschäftslogikklasse umfasst sowohl Geschäftslogikmethoden als auch Datenzugriffsmethoden, aber die Datenzugriffsmethoden rufen das Repository auf, um Datenzugriffsaufgaben auszuführen.

Sie erstellen auch eine Abstraktionsebene zwischen BLL und DAL, die automatisierte Komponententests der BLL ermöglicht. Diese Abstraktionsebene wird implementiert, indem Sie eine Schnittstelle erstellen und die Schnittstelle verwenden, wenn Sie das Repository in der Geschäftslogikklasse instanziieren. Dadurch können Sie die Geschäftslogikklasse mit einem Verweis auf jedes Objekt bereitstellen, das die Repositoryschnittstelle implementiert. Für den normalen Betrieb stellen Sie ein Repositoryobjekt bereit, das mit Entity Framework funktioniert. Zu Testzwecken stellen Sie ein Repositoryobjekt bereit, das mit Daten arbeitet, die so gespeichert sind, dass Sie sie einfach bearbeiten können, z. B. Klassenvariablen, die als Sammlungen definiert sind.

Die folgende Abbildung zeigt den Unterschied zwischen einer Geschäftslogikklasse, die Datenzugriffslogik ohne Repository enthält, und einer Klasse, die ein Repository verwendet.

Image05

Sie erstellen zunächst Webseiten, auf denen das ObjectDataSource Steuerelement direkt an ein Repository gebunden ist, da es nur grundlegende Datenzugriffsaufgaben ausführt. Im nächsten Tutorial erstellen Sie eine Geschäftslogikklasse mit Validierungslogik und binden das ObjectDataSource Steuerelement an diese Klasse statt an die Repositoryklasse. Außerdem erstellen Sie Komponententests für die Validierungslogik. Im dritten Tutorial dieser Reihe fügen Sie der Anwendung Sortier- und Filterfunktionen hinzu.

Die Seiten, die Sie in diesem Tutorial erstellen, arbeiten mit dem Departments Entitätssatz des Datenmodells zusammen, das Sie in der Tutorialreihe Erste Schritte erstellt haben.

Screenshot, der zeigt, wie Ihre Abteilungsseite aussehen sollte.

Image02

Aktualisieren der Datenbank und des Datenmodells

Sie beginnen dieses Tutorial mit zwei Änderungen an der Datenbank, die beide entsprechende Änderungen am Datenmodell erfordern, das Sie im Erste Schritte mit dem Entity Framework und Web Forms Tutorials erstellt haben. In einem dieser Tutorials haben Sie änderungen im Designer manuell vorgenommen, um das Datenmodell nach einer Datenbankänderung mit der Datenbank zu synchronisieren. In diesem Tutorial verwenden Sie das Tool Modell aus Datenbank aktualisieren des Designers, um das Datenmodell automatisch zu aktualisieren.

Hinzufügen einer Beziehung zur Datenbank

Öffnen Sie in Visual Studio die Webanwendung contoso University, die Sie im Erste Schritte mit den Tutorialreihen Entity Framework und Web Forms erstellt haben, und öffnen Sie dann das SchoolDiagram Datenbankdiagramm.

Wenn Sie sich die Department Tabelle im Datenbankdiagramm ansehen, sehen Sie, dass sie über eine Administrator Spalte verfügt. Diese Spalte ist ein Fremdschlüssel für die Person Tabelle, aber in der Datenbank ist keine Fremdschlüsselbeziehung definiert. Sie müssen die Beziehung erstellen und das Datenmodell aktualisieren, damit Entity Framework diese Beziehung automatisch verarbeiten kann.

Klicken Sie im Datenbankdiagramm mit der rechten Maustaste auf die Department Tabelle, und wählen Sie Beziehungen aus.

Image80

Klicken Sie im Feld Fremdschlüsselbeziehungen auf Hinzufügen, und klicken Sie dann auf die Auslassungspunkte für Tabellen- und Spaltenspezifikation.

Bild81

Legen Sie im Dialogfeld Tabellen und Spalten die Primärschlüsseltabelle und das Primärschlüsselfeld auf Person und PersonIDfest, und legen Sie die Fremdschlüsseltabelle und das Feld auf und AdministratorfestDepartment. (Wenn Sie dies tun, ändert sich der Beziehungsname von FK_Department_Department in FK_Department_Person.)

Bild82

Klicken Sie im Feld Tabellen und Spalten auf OK, klicken Sie im Feld Fremdschlüsselbeziehungen auf Schließen, und speichern Sie die Änderungen. Wenn Sie gefragt werden, ob Sie die Person Tabellen und Department speichern möchten, klicken Sie auf Ja.

Hinweis

Wenn Sie Zeilen gelöscht Person haben, die Daten entsprechen, die sich bereits in der Administrator Spalte befinden, können Sie diese Änderung nicht speichern. Verwenden Sie in diesem Fall den Tabellen-Editor in Server Explorer, um sicherzustellen, dass der Administrator Wert in jeder Department Zeile die ID eines Datensatzes enthält, der tatsächlich in der Person Tabelle vorhanden ist.

Nachdem Sie die Änderung gespeichert haben, können Sie keine Zeile aus der Person Tabelle löschen, wenn diese Person ein Abteilungsadministrator ist. In einer Produktionsanwendung würden Sie eine bestimmte Fehlermeldung bereitstellen, wenn eine Datenbankeinschränkung ein Löschen verhindert, oder Sie würden einen kaskadierenden Löschvorgang angeben. Ein Beispiel zum Angeben eines kaskadierenden Löschvorgangs finden Sie unter Entity Framework und ASP.NET – Erste Schritte Teil 2.

Hinzufügen einer Ansicht zur Datenbank

Auf der neuen Seite Departments.aspx , die Sie erstellen, möchten Sie eine Dropdownliste mit Kursleitern mit Namen im Format "last, first" bereitstellen, damit Benutzer Abteilungsadministratoren auswählen können. Um dies zu vereinfachen, erstellen Sie eine Ansicht in der Datenbank. Die Ansicht besteht nur aus den Für die Dropdownliste benötigten Daten: dem vollständigen Namen (ordnungsgemäß formatiert) und dem Datensatzschlüssel.

Erweitern Sie unter Server Explorerden Eintrag School.mdf, klicken Sie mit der rechten Maustaste auf den Ordner Ansichten, und wählen Sie Neue Ansicht hinzufügen aus.

Abbildung06

Klicken Sie auf Schließen , wenn das Dialogfeld Tabelle hinzufügen angezeigt wird, und fügen Sie die folgende SQL-Anweisung in den SQL-Bereich ein:

SELECT        LastName + ',' + FirstName AS FullName, PersonID
FROM          dbo.Person
WHERE        (HireDate IS NOT NULL)

Speichern Sie die Ansicht unter vInstructorName.

Aktualisieren des Datenmodells

Öffnen Sie im Ordner DAL die Datei SchoolModel.edmx , klicken Sie mit der rechten Maustaste auf die Entwurfsoberfläche, und wählen Sie Modell aus Datenbank aktualisieren aus.

Image07

Wählen Sie im Dialogfeld Datenbankobjekte auswählen die Registerkarte Hinzufügen aus, und wählen Sie die soeben erstellte Ansicht aus.

Image08

Klicken Sie auf Fertig stellen.

Im Designer sehen Sie, dass das Tool eine vInstructorName Entität und eine neue Zuordnung zwischen den Department Entitäten und Person erstellt hat.

Bild13

Hinweis

In den Fenstern Ausgabe - und Fehlerliste wird möglicherweise eine Warnmeldung angezeigt, die Sie darüber informiert, dass das Tool automatisch einen Primärschlüssel für die neue vInstructorName Ansicht erstellt hat. Dieses Verhalten wird erwartet.

Wenn Sie im Code auf die neue vInstructorName Entität verweisen, sollten Sie nicht die Datenbankkonvention verwenden, der ein kleingeschriebenes "v" vorangestellt wird. Daher benennen Sie die entitäts- und entitätssatz im Modell um.

Öffnen Sie den Modellbrowser. Sie werden vInstructorName als Entitätstyp und Ansicht aufgeführt.

Bild14

Klicken Sie unter SchoolModel (nicht SchoolModel.Store) mit der rechten Maustaste auf vInstructorName , und wählen Sie Eigenschaften aus. Ändern Sie im Eigenschaftenfenster die Name-Eigenschaft in "InstructorName", und ändern Sie die Eigenschaft Entitätssatzname in "InstructorNames".

Bild15

Speichern und schließen Sie das Datenmodell, und erstellen Sie das Projekt dann neu.

Verwenden einer Repositoryklasse und eines ObjectDataSource-Steuerelements

Erstellen Sie eine neue Klassendatei im DAL-Ordner , nennen Sie sie SchoolRepository.cs, und ersetzen Sie den vorhandenen Code durch den folgenden Code:

using System;
using System.Collections.Generic;
using System.Linq;
using ContosoUniversity.DAL;

namespace ContosoUniversity.DAL
{
    public class SchoolRepository : IDisposable
    {
        private SchoolEntities context = new SchoolEntities();

        public IEnumerable<Department> GetDepartments()
        {
            return context.Departments.Include("Person").ToList();
        }

        private bool disposedValue = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposedValue)
            {
                if (disposing)
                {
                    context.Dispose();
                }
            }
            this.disposedValue = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

    }
}

Dieser Code stellt eine einzelne GetDepartments Methode bereit, die alle Entitäten im Entitätssatz Departments zurückgibt. Da Sie wissen, dass Sie für jede zurückgegebene Zeile auf die Person Navigationseigenschaft zugreifen, geben Sie für diese Eigenschaft mithilfe der -Methode das eifrige Laden an Include . Die -Klasse implementiert auch die IDisposable Schnittstelle, um sicherzustellen, dass die Datenbankverbindung freigegeben wird, wenn das Objekt verworfen wird.

Hinweis

Eine gängige Praxis besteht darin, eine Repositoryklasse für jeden Entitätstyp zu erstellen. In diesem Tutorial wird eine Repositoryklasse für mehrere Entitätstypen verwendet. Weitere Informationen zum Repositorymuster finden Sie in den Beiträgen im Blog des Entity Framework-Teams und im Blog von Julie Lerman.

Die GetDepartments -Methode gibt ein IEnumerable -Objekt und kein IQueryable -Objekt zurück, um sicherzustellen, dass die zurückgegebene Auflistung auch nach der Entsorgung des Repositoryobjekts verwendet werden kann. Ein IQueryable Objekt kann bei jedem Zugriff auf den Datenbankzugriff führen, aber das Repositoryobjekt kann verworfen werden, wenn ein datengebundenes Steuerelement versucht, die Daten zu rendern. Sie können einen anderen Auflistungstyp zurückgeben, z. B. ein IList -Objekt anstelle eines IEnumerable -Objekts. Durch das Zurückgeben eines IEnumerable -Objekts wird jedoch sichergestellt, dass Sie typische schreibgeschützte Listenverarbeitungsaufgaben wie foreach Schleifen und LINQ-Abfragen ausführen können. Sie können jedoch keine Elemente in der Auflistung hinzufügen oder entfernen, was bedeuten könnte, dass solche Änderungen in der Datenbank beibehalten würden.

Erstellen Sie eine Departments.aspx-Seite, die die Seite Site.Master master verwendet, und fügen Sie dem Steuerelement das folgende Markup mit dem Content Namen hinzuContent2:

<h2>Departments</h2>
    <asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.DAL.SchoolRepository" 
        DataObjectTypeName="ContosoUniversity.DAL.Department" 
        SelectMethod="GetDepartments" >
    </asp:ObjectDataSource>
    <asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
        DataSourceID="DepartmentsObjectDataSource"  >
        <Columns>
            <asp:CommandField ShowEditButton="True" ShowDeleteButton="True"
                ItemStyle-VerticalAlign="Top">
            </asp:CommandField>
            <asp:DynamicField DataField="Name" HeaderText="Name" SortExpression="Name" ItemStyle-VerticalAlign="Top" />
            <asp:DynamicField DataField="Budget" HeaderText="Budget" SortExpression="Budget" ItemStyle-VerticalAlign="Top" />
            <asp:DynamicField DataField="StartDate" HeaderText="Start Date" ItemStyle-VerticalAlign="Top" />
            <asp:TemplateField HeaderText="Administrator" SortExpression="Person.LastName" ItemStyle-VerticalAlign="Top" >
                <ItemTemplate>
                    <asp:Label ID="AdministratorLastNameLabel" runat="server" Text='<%# Eval("Person.LastName") %>'></asp:Label>,
                    <asp:Label ID="AdministratorFirstNameLabel" runat="server" Text='<%# Eval("Person.FirstMidName") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

Dieses Markup erstellt ein ObjectDataSource Steuerelement, das die soeben erstellte Repositoryklasse verwendet, und ein GridView Steuerelement zum Anzeigen der Daten. Das GridView Steuerelement gibt Die Befehle Bearbeiten und Löschen an, aber Sie haben noch keinen Code hinzugefügt, um sie zu unterstützen.

Mehrere Spalten verwenden DynamicField Steuerelemente, sodass Sie von der automatischen Datenformatierungs- und Validierungsfunktion profitieren können. Damit diese funktionieren, müssen Sie die EnableDynamicData -Methode im Page_Init Ereignishandler aufrufen. (DynamicControl Steuerelemente werden im Administrator Feld nicht verwendet, da sie nicht mit Navigationseigenschaften funktionieren.)

Die Vertical-Align="Top" Attribute werden später wichtig, wenn Sie dem Raster eine Spalte mit einem geschachtelten GridView Steuerelement hinzufügen.

Öffnen Sie die Datei Departments.aspx.cs, und fügen Sie die folgende using Anweisung hinzu:

using ContosoUniversity.DAL;

Fügen Sie dann den folgenden Handler für das Ereignis der Seite Init hinzu:

protected void Page_Init(object sender, EventArgs e)
{
    DepartmentsGridView.EnableDynamicData(typeof(Department));
}

Erstellen Sie im Ordner DAL eine neue Klassendatei mit dem Namen Department.cs , und ersetzen Sie den vorhandenen Code durch den folgenden Code:

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace ContosoUniversity.DAL
{
    [MetadataType(typeof(DepartmentMetaData))]
    public partial class Department
    {
    }

    public class DepartmentMetaData
    {
        [DataType(DataType.Currency)]
        [Range(0, 1000000, ErrorMessage = "Budget must be less than $1,000,000.00")]
        public Decimal Budget { get; set; }

        [DisplayFormat(DataFormatString="{0:d}",ApplyFormatInEditMode=true)]
        public DateTime StartDate { get; set; }

    }
}

Dieser Code fügt dem Datenmodell Metadaten hinzu. Es gibt an, dass die Budget Eigenschaft der Department Entität tatsächlich eine Währung darstellt, obwohl ihr Datentyp ist Decimal, und gibt an, dass der Wert zwischen 0 und 1.000.000,00 USD betragen muss. Außerdem wird angegeben, dass die StartDate Eigenschaft als Datum im Format mm/tt/jjjj formatiert werden soll.

Führen Sie die Seite Departments.aspx aus.

Screenshot, der die Seite

Beachten Sie, dass Sie zwar keine Formatzeichenfolge im Departments.aspx-Seitenmarkup für die Spalten Budget oder Startdatum angegeben haben, die Standardformatierung der Währung und des Datums jedoch von den DynamicField Steuerelementen auf sie angewendet wurde, indem Sie die Metadaten verwenden, die Sie in der Datei Department.cs angegeben haben.

Hinzufügen von Einfüge- und Löschfunktionen

Öffnen Sie SchoolRepository.cs, und fügen Sie den folgenden Code hinzu, um eine Insert Methode und eine Delete Methode zu erstellen. Der Code enthält auch eine Methode namens GenerateDepartmentID , die den nächsten verfügbaren Datensatzschlüsselwert für die Verwendung durch die Insert -Methode berechnet. Dies ist erforderlich, da die Datenbank nicht für die automatische Berechnung für die Department Tabelle konfiguriert ist.

public void InsertDepartment(Department department)
{
    try
    {
        department.DepartmentID = GenerateDepartmentID();
        context.Departments.AddObject(department);
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        //Include catch blocks for specific exceptions first,
        //and handle or log the error as appropriate in each.
        //Include a generic catch block like this one last.
        throw ex;
    }
}

public void DeleteDepartment(Department department)
{
    try
    {
        context.Departments.Attach(department);
        context.Departments.DeleteObject(department);
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        //Include catch blocks for specific exceptions first,
        //and handle or log the error as appropriate in each.
        //Include a generic catch block like this one last.
        throw ex;
    }
}

private Int32 GenerateDepartmentID()
{
    Int32 maxDepartmentID = 0;
    var department = (from d in GetDepartments()
                      orderby d.DepartmentID descending
                      select d).FirstOrDefault();
    if (department != null)
    {
        maxDepartmentID = department.DepartmentID + 1;
    }
    return maxDepartmentID;
}

Die Attach-Methode

Die DeleteDepartment -Methode ruft die Attach -Methode auf, um den Link erneut herzustellen, der im Objektstatus-Manager des Objektkontexts zwischen der Entität im Arbeitsspeicher und der Datenbankzeile, die sie darstellt, beibehalten wird. Dies muss erfolgen, bevor die -Methode die SaveChanges -Methode aufruft.

Der Begriff Objektkontext bezieht sich auf die Entity Framework-Klasse, die von der ObjectContext Klasse abgeleitet wird, die Sie für den Zugriff auf Ihre Entitätssätze und Entitäten verwenden. Im Code für dieses Projekt heißt SchoolEntitiesdie -Klasse , und ein instance davon ist immer benanntcontext. Der Objektstatus-Manager des Objektkontexts ist eine Klasse, die von der ObjectStateManager -Klasse abgeleitet ist. Der Objektkontakt verwendet den Objektzustands-Manager, um Entitätsobjekte zu speichern und nachzuverfolgen, ob jedes Objekt mit der entsprechenden Tabellenzeile oder den entsprechenden Zeilen in der Datenbank synchronisiert ist.

Wenn Sie eine Entität lesen, speichert der Objektkontext sie im Objektstatus-Manager und verfolgt, ob diese Darstellung des Objekts mit der Datenbank synchronisiert ist. Wenn Sie beispielsweise einen Eigenschaftswert ändern, wird ein Flag festgelegt, um anzugeben, dass die geänderte Eigenschaft nicht mehr mit der Datenbank synchronisiert ist. Wenn Sie dann die SaveChanges -Methode aufrufen, weiß der Objektkontext, was in der Datenbank zu tun ist, da der Objektstatus-Manager genau weiß, was sich zwischen dem aktuellen Zustand der Entität und dem Zustand der Datenbank unterscheidet.

Dieser Prozess funktioniert jedoch in einer Webanwendung in der Regel nicht, da der Objektkontext instance, der eine Entität liest, zusammen mit allem im Objektstatus-Manager, nach dem Rendern einer Seite verworfen wird. Der Objektkontext instance, der Änderungen anwenden muss, ist ein neuer Kontext, der für die Postbackverarbeitung instanziiert wird. Im Fall der DeleteDepartment -Methode erstellt das Steuerelement die ObjectDataSource ursprüngliche Version der Entität für Sie aus Werten im Ansichtszustand neu, aber diese neu erstellte Department Entität ist im Objektzustands-Manager nicht vorhanden. Wenn Sie die DeleteObject Methode für diese neu erstellte Entität aufgerufen haben, schlägt der Aufruf fehl, da der Objektkontext nicht weiß, ob die Entität mit der Datenbank synchronisiert ist. Durch das Aufrufen der Attach -Methode wird jedoch die gleiche Nachverfolgung zwischen der neu erstellten Entität und den Werten in der Datenbank wie beim Lesen der Entität in einer früheren instance des Objektkontexts erneut eingerichtet.

Es gibt Zeiten, in denen sie nicht möchten, dass der Objektkontext Entitäten im Objektstatus-Manager nachverfolgt, und Sie können Flags festlegen, um dies zu verhindern. Beispiele hierfür werden in späteren Tutorials dieser Reihe gezeigt.

Die SaveChanges-Methode

Diese einfache Repositoryklasse veranschaulicht grundlegende Prinzipien zum Ausführen von CRUD-Vorgängen. In diesem Beispiel wird die SaveChanges -Methode sofort nach jedem Update aufgerufen. In einer Produktionsanwendung sollten Sie die SaveChanges -Methode von einer separaten Methode aufrufen, um mehr Kontrolle darüber zu erhalten, wann die Datenbank aktualisiert wird. (Am Ende des nächsten Tutorials finden Sie einen Link zu einem Whitepaper, in dem das Arbeitseinheitsmuster erläutert wird, bei dem es sich um einen Ansatz zur Koordinierung verwandter Updates handelt.) Beachten Sie auch, dass die -Methode im Beispiel keinen Code für die DeleteDepartment Behandlung von Parallelitätskonflikten enthält. Code dazu wird in einem späteren Tutorial dieser Reihe hinzugefügt.

Abrufen von Kursleiternamen, die beim Einfügen ausgewählt werden sollen

Benutzer müssen in der Lage sein, einen Administrator aus einer Liste von Kursleitern in einer Dropdownliste auszuwählen, wenn neue Abteilungen erstellt werden. Fügen Sie daher schoolRepository.cs den folgenden Code hinzu, um eine Methode zum Abrufen der Liste der Kursleiter mithilfe der zuvor erstellten Ansicht zu erstellen:

public IEnumerable<InstructorName> GetInstructorNames()
{
    return context.InstructorNames.OrderBy("it.FullName").ToList();
}

Erstellen einer Seite zum Einfügen von Abteilungen

Erstellen Sie eine DepartmentsAdd.aspx-Seite , die die Seite Site.Master verwendet, und fügen Sie dem Steuerelement das folgende Markup mit dem Content Namen Content2hinzu:

<h2>Departments</h2>
    <asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.DAL.SchoolRepository" DataObjectTypeName="ContosoUniversity.DAL.Department"
        InsertMethod="InsertDepartment" >
    </asp:ObjectDataSource>
    <asp:DetailsView ID="DepartmentsDetailsView" runat="server" 
        DataSourceID="DepartmentsObjectDataSource" AutoGenerateRows="False"
        DefaultMode="Insert" OnItemInserting="DepartmentsDetailsView_ItemInserting">
        <Fields>
            <asp:DynamicField DataField="Name" HeaderText="Name" />
            <asp:DynamicField DataField="Budget" HeaderText="Budget" />
            <asp:DynamicField DataField="StartDate" HeaderText="Start Date" />
            <asp:TemplateField HeaderText="Administrator">
                <InsertItemTemplate>
                    <asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server" 
                        TypeName="ContosoUniversity.DAL.SchoolRepository" 
                        DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
                        SelectMethod="GetInstructorNames" >
                    </asp:ObjectDataSource>
                    <asp:DropDownList ID="InstructorsDropDownList" runat="server" 
                        DataSourceID="InstructorsObjectDataSource"
                        DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init">
                    </asp:DropDownList>
                </InsertItemTemplate>
            </asp:TemplateField>
            <asp:CommandField ShowInsertButton="True" />
        </Fields>
    </asp:DetailsView>
   <asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server" 
        ShowSummary="true" DisplayMode="BulletList"  />

Dieses Markup erstellt zwei ObjectDataSource Steuerelemente, eines zum Einfügen neuer Department Entitäten und eines zum Abrufen von Kursleiternamen für das Steuerelement, das für die DropDownList Auswahl von Abteilungsadministratoren verwendet wird. Das Markup erstellt ein DetailsView Steuerelement zum Eingeben neuer Abteilungen und gibt einen Handler für das Ereignis des Steuerelements ItemInserting an, damit Sie den Administrator Fremdschlüsselwert festlegen können. Am Ende befindet sich ein ValidationSummary Steuerelement zum Anzeigen von Fehlermeldungen.

Öffnen Sie DepartmentsAdd.aspx.cs , und fügen Sie die folgende using Anweisung hinzu:

using ContosoUniversity.DAL;

Fügen Sie die folgenden Klassenvariablen und -methoden hinzu:

private DropDownList administratorsDropDownList;

protected void Page_Init(object sender, EventArgs e)
{
    DepartmentsDetailsView.EnableDynamicData(typeof(Department));
}

protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
    administratorsDropDownList = sender as DropDownList;
}

protected void DepartmentsDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
    e.Values["Administrator"] = administratorsDropDownList.SelectedValue;
}

Die Page_Init -Methode aktiviert Dynamic Data-Funktionalität. Der Handler für das -Ereignis des DropDownList Steuerelements Init speichert einen Verweis auf das Steuerelement, und der Handler für das -Ereignis des DetailsView Steuerelements verwendet diesen Verweis, um den PersonID Wert des ausgewählten Kursleiters Inserting abzurufen und die Administrator Fremdschlüsseleigenschaft der Department Entität zu aktualisieren.

Führen Sie die Seite aus, fügen Sie Informationen für eine neue Abteilung hinzu, und klicken Sie dann auf den Link Einfügen .

Image04

Geben Sie Werte für eine andere neue Abteilung ein. Geben Sie im Feld Budget eine Zahl größer als 1.000.000,00 ein, und klicken Sie auf die Registerkarte zum nächsten Feld. Im Feld wird ein Sternchen angezeigt, und wenn Sie den Mauszeiger darüber halten, sehen Sie die Fehlermeldung, die Sie in die Metadaten für dieses Feld eingegeben haben.

Image03

Klicken Sie auf Einfügen, und Sie sehen die Fehlermeldung, die ValidationSummary vom Steuerelement am unteren Rand der Seite angezeigt wird.

Bild12

Schließen Sie als Nächstes den Browser, und öffnen Sie die Seite Departments.aspx . Fügen Sie der Seite Departments.aspx die Löschfunktion hinzu, indem Sie dem ObjectDataSource Steuerelement ein DeleteMethod Attribut und dem Steuerelement ein DataKeyNames Attribut GridView hinzufügen. Die öffnenden Tags für diese Steuerelemente ähneln nun dem folgenden Beispiel:

<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.DAL.SchoolRepository" 
        DataObjectTypeName="ContosoUniversity.DAL.Department"
        SelectMethod="GetDepartments" 
        DeleteMethod="DeleteDepartment" >

    <asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
        DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID" >

Führen Sie die Seite aus.

Screenshot, der die Seite

Löschen Sie die Abteilung, die Sie beim Ausführen der Seite DepartmentsAdd.aspx hinzugefügt haben.

Hinzufügen von Updatefunktionen

Öffnen Sie SchoolRepository.cs , und fügen Sie die folgende Update Methode hinzu:

public void UpdateDepartment(Department department, Department origDepartment)
{
    try
    {
        context.Departments.Attach(origDepartment);
        context.ApplyCurrentValues("Departments", department);
        context.SaveChanges();
    }
    catch (Exception ex)
    {
        //Include catch blocks for specific exceptions first,
        //and handle or log the error as appropriate in each.
        //Include a generic catch block like this one last.
        throw ex;
    }
}

Wenn Sie auf der Seite Departments.aspx auf Aktualisieren klicken, erstellt das ObjectDataSource Steuerelement zwei Department Entitäten, die an die UpdateDepartment -Methode übergeben werden sollen. Einer enthält die ursprünglichen Werte, die im Ansichtszustand gespeichert wurden, und der andere enthält die neuen Werte, die in das GridView Steuerelement eingegeben wurden. Der Code in der UpdateDepartment -Methode übergibt die Department Entität, die über die ursprünglichen Werte verfügt, an die Attach -Methode, um die Nachverfolgung zwischen der Entität und dem, was sich in der Datenbank befindet, einzurichten. Anschließend übergibt der Code die Department Entität, die über die neuen Werte verfügt, an die ApplyCurrentValues -Methode. Der Objektkontext vergleicht die alten und neuen Werte. Wenn sich ein neuer Wert von einem alten Wert unterscheidet, ändert der Objektkontext den Eigenschaftswert. Die SaveChanges -Methode aktualisiert dann nur die geänderten Spalten in der Datenbank. (Wenn die Updatefunktion für diese Entität jedoch einer gespeicherten Prozedur zugeordnet wäre, würde die gesamte Zeile unabhängig davon aktualisiert, welche Spalten geändert wurden.)

Öffnen Sie die Datei Departments.aspx , und fügen Sie dem Steuerelement die DepartmentsObjectDataSource folgenden Attribute hinzu:

  • UpdateMethod="UpdateDepartment"
  • ConflictDetection="CompareAllValues"
    Dadurch werden alte Werte im Ansichtszustand gespeichert, sodass sie mit den neuen Werten in der Update -Methode verglichen werden können.
  • OldValuesParameterFormatString="orig{0}"
    Dadurch wird das Steuerelement darüber informiert, dass der Name des ursprünglichen values-Parameters lautet origDepartment .

Das Markup für das öffnende Tag des ObjectDataSource Steuerelements ähnelt nun dem folgenden Beispiel:

<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server" 
        TypeName="ContosoUniversity.DAL.SchoolRepository" 
        DataObjectTypeName="ContosoUniversity.DAL.Department" 
        SelectMethod="GetDepartments" DeleteMethod="DeleteDepartment" 
        UpdateMethod="UpdateDepartment"
        ConflictDetection="CompareAllValues" 
        OldValuesParameterFormatString="orig{0}" >

Fügen Sie dem GridView Steuerelement ein OnRowUpdating="DepartmentsGridView_RowUpdating" Attribut hinzu. Sie verwenden dies, um den Administrator Eigenschaftswert basierend auf der Zeile festzulegen, die der Benutzer in einer Dropdownliste auswählt. Das GridView öffnende Tag ähnelt nun dem folgenden Beispiel:

<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
        DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID"
        OnRowUpdating="DepartmentsGridView_RowUpdating">

Fügen Sie dem Steuerelement unmittelbar nach dem GridView Steuerelement für diese Administrator Spalte ein Steuerelement für die ItemTemplate Spalte hinzuEditItemTemplate:

<EditItemTemplate>
                    <asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server" DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
                        SelectMethod="GetInstructorNames" TypeName="ContosoUniversity.DAL.SchoolRepository">
                    </asp:ObjectDataSource>
                    <asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsObjectDataSource"
                        SelectedValue='<%# Eval("Administrator")  %>'
                        DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init" >
                    </asp:DropDownList>
                </EditItemTemplate>

Dieses EditItemTemplate Steuerelement ähnelt dem InsertItemTemplate Steuerelement auf der Seite DepartmentsAdd.aspx . Der Unterschied besteht darin, dass der Anfangswert des Steuerelements mithilfe des SelectedValue -Attributs festgelegt wird.

Fügen Sie vor dem GridView Steuerelement wie auf der Seite DepartmentsAdd.aspx ein ValidationSummary Steuerelement hinzu.

<asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server" 
        ShowSummary="true" DisplayMode="BulletList"  />

Öffnen Sie Departments.aspx.cs , und fügen Sie unmittelbar nach der partiellen Klassendeklaration den folgenden Code hinzu, um ein privates Feld zu erstellen, das auf das DropDownList Steuerelement verweist:

private DropDownList administratorsDropDownList;

Fügen Sie dann Handler für das DropDownList -Ereignis des Steuerelements Init und das GridView -Ereignis des Steuerelements RowUpdating hinzu:

protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
    administratorsDropDownList = sender as DropDownList;
}

protected void DepartmentsGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    e.NewValues["Administrator"] = administratorsDropDownList.SelectedValue;
}

Der Handler für das Init Ereignis speichert einen Verweis auf das DropDownList -Steuerelement im Klassenfeld. Der Handler für das RowUpdating Ereignis verwendet den Verweis, um den vom Benutzer eingegebenen Wert abzurufen und auf die Administrator -Eigenschaft der Department Entität anzuwenden.

Verwenden Sie die Seite DepartmentsAdd.aspx , um eine neue Abteilung hinzuzufügen, führen Sie dann die Seite Departments.aspx aus, und klicken Sie in der hinzugefügten Zeile auf Bearbeiten .

Hinweis

Sie können keine Zeilen bearbeiten, die Sie nicht hinzugefügt haben (d. a. die sich bereits in der Datenbank befanden), da ungültige Daten in der Datenbank vorhanden sind. Die Administratoren für die Zeilen, die mit der Datenbank erstellt wurden, sind Studenten. Wenn Sie versuchen, eine davon zu bearbeiten, erhalten Sie eine Fehlerseite, die einen Fehler meldet, z. B. 'InstructorsDropDownList' has a SelectedValue which is invalid because it does not exist in the list of items.

Bild 10

Wenn Sie einen ungültigen Budgetbetrag eingeben und dann auf Aktualisieren klicken, wird das gleiche Sternchen und die gleiche Fehlermeldung angezeigt, die Sie auf der Seite Departments.aspx angezeigt haben.

Ändern Sie einen Feldwert, oder wählen Sie einen anderen Administrator aus, und klicken Sie auf Aktualisieren. Die Änderung wird angezeigt.

Screenshot: Seite

Dies schließt die Einführung in die Verwendung des ObjectDataSource Steuerelements für grundlegende CRUD-Vorgänge (Erstellen, Lesen, Aktualisieren, Löschen) mit Entity Framework ab. Sie haben eine einfache n-Schicht-Anwendung erstellt, aber die Geschäftslogikebene ist immer noch eng mit der Datenzugriffsebene verknüpft, was automatisierte Komponententests erschwert. Im folgenden Tutorial erfahren Sie, wie Sie das Repositorymuster implementieren, um Komponententests zu vereinfachen.