Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Von Tom Dykstra
Diese Lernprogrammreihe basiert auf der Contoso University-Webanwendung, die von der Lernprogrammreihe "Getting Started with the Entity Framework 4.0 " erstellt wird. Wenn Sie die früheren Lernprogramme nicht abgeschlossen haben, können Sie als Ausgangspunkt für dieses Lernprogramm die Anwendung herunterladen , die Sie erstellt haben. Sie können auch die Anwendung herunterladen , die von der vollständigen Lernprogrammreihe erstellt wird.
Die Contoso University-Beispielwebanwendung veranschaulicht, wie ASP.NET Web Forms-Anwendungen mithilfe von Entity Framework 4.0 und Visual Studio 2010 erstellt werden. 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 Lernprogramm zeigt Beispiele in C#. Das herunterladbare Beispiel enthält Code in C# und Visual Basic.
Datenbank zuerst
Es gibt drei Möglichkeiten zum Arbeiten mit Daten im Entity Framework: Database First, Model First und Code First. Dieses Tutorial ist für "Database First" gedacht. Informationen zu den Unterschieden zwischen diesen Workflows und Anleitungen zum Auswählen des besten für Ihr Szenarios finden Sie unter Entity Framework Development Workflows.
Webformulare
Wie die Reihe "Erste Schritte" verwendet diese Lernprogrammreihe das ASP.NET Web Forms-Modell und geht davon aus, 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 die ersten Schritte mit dem Entity Framework mit ASP.NET MVC.
Softwareversionen
Im Lernprogramm gezeigt Funktioniert auch mit Windows 7 Windows 8 Visual Studio 2010 Visual Studio 2010 Express for Web. Das Lernprogramm wurde mit späteren Versionen von Visual Studio nicht getestet. Es gibt viele Unterschiede bei den Menüauswahlen, Dialogfeldern und Vorlagen. .NET 4 .NET 4.5 ist abwärtskompatibel mit .NET 4, das Lernprogramm wurde jedoch nicht mit .NET 4.5 getestet. Entity Framework 4 Das Lernprogramm wurde nicht mit späteren Versionen von Entity Framework getestet. Ab Entity Framework 5 verwendet EF standardmäßig das DbContext APImit EF 4.1 eingeführte Element. Das EntityDataSource-Steuerelement wurde für die Verwendung derObjectContextAPI entwickelt. Informationen zur Verwendung des EntityDataSource-Steuerelements mit derDbContextAPI finden Sie in diesem Blogbeitrag.Fragen
Wenn Sie Fragen haben, die sich nicht direkt auf das Lernprogramm beziehen, können Sie sie im Forum ASP.NET Entity Framework, dem Forum "Entity Framework" und " LINQ to Entities" veröffentlichen oder StackOverflow.com.
Mit dem EntityDataSource Steuerelement können Sie eine Anwendung sehr schnell erstellen, aber in der Regel müssen Sie eine erhebliche Menge an Geschäftslogik und Datenzugriffslogik auf Ihren .aspx Seiten beibehalten. Wenn Sie davon ausgehen, dass Ihre Anwendung komplexer wird und fortlaufende Wartung erfordert, können Sie im Vorfeld mehr Entwicklungszeit investieren, um eine n-stufige oder mehrschichtige Anwendungsstruktur zu erstellen, die besser verwaltet werden kann. Um diese Architektur zu implementieren, trennen Sie die Präsentationsschicht von der Geschäftslogikebene (Business Logic Layer, BLL) und der Datenzugriffsschicht (DATA Access Layer, DAL). Eine Möglichkeit zum Implementieren dieser Struktur ist die Verwendung des ObjectDataSource Steuerelements anstelle des EntityDataSource Steuerelements. Wenn Sie das ObjectDataSource Steuerelement verwenden, implementieren Sie Ihren eigenen Datenzugriffscode und rufen ihn dann auf .aspx Seiten mithilfe eines Steuerelements auf, das viele der gleichen Features wie andere Datenquellensteuerelemente enthält. 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.
Das ObjectDataSource Steuerelement bietet Ihnen mehr Flexibilität auf andere Weise. 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, die das EntityDataSource Steuerelement ausführen soll. Beispielsweise können Sie die Protokollierung jedes Mal durchführen, wenn eine Entität aktualisiert wird, Daten archivieren, wenn eine Entität gelöscht wird, oder bei Bedarf verwandte Daten überprüfen und aktualisieren, wenn eine Zeile mit einem Fremdschlüsselwert eingefügt wird.
Geschäftslogik und Repositoryklassen
Ein ObjectDataSource Steuerelement funktioniert durch Aufrufen einer von Ihnen erstellten Klasse. Die Klasse enthält Methoden zum Abrufen und Aktualisieren von Daten, und Sie stellen die Namen dieser Methoden für das ObjectDataSource Steuerelement im Markup bereit. Während der Rendering- oder Postbackverarbeitung ruft das ObjectDataSource die 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 die ObjectDataSource Daten 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 ObjectDataSource-Klassenübersicht, ruft das Steuerelement eine Klasse auf, die als Geschäftsobjekt bezeichnet wird, das sowohl Geschäftslogik als auch Datenzugriffslogik enthält. In diesem Lernprogramm erstellen Sie separate Klassen für Geschäftslogik und datenzugriffslogik. Die Klasse, die datenzugriffslogik kapselt, wird als Repository bezeichnet. Die Geschäftslogikklasse enthält 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 erleichtert. Diese Abstraktionsebene wird implementiert, indem eine Schnittstelle erstellt und die Schnittstelle verwendet wird, wenn Sie das Repository in der Geschäftslogikklasse instanziieren. Auf diese Weise können Sie die Geschäftslogikklasse mit einem Verweis auf jedes Objekt bereitstellen, das die Repositoryschnittstelle implementiert. Für den normalen Vorgang stellen Sie ein Repositoryobjekt bereit, das mit Entity Framework funktioniert. Zum Testen stellen Sie ein Repositoryobjekt bereit, das mit Daten funktioniert, die auf einfache Weise gespeichert sind, z. B. Klassenvariablen, die als Sammlungen definiert sind.
Die folgende Abbildung zeigt den Unterschied zwischen einer Geschäftslogikklasse, die Datenzugriffslogik ohne ein Repository enthält, und einer, die ein Repository verwendet.
Sie beginnen mit dem Erstellen von Webseiten, auf denen das ObjectDataSource Steuerelement direkt an ein Repository gebunden ist, da es nur grundlegende Datenzugriffsaufgaben ausführt. Im nächsten Lernprogramm erstellen Sie eine Geschäftslogikklasse mit Validierungslogik und binden das Steuerelement an diese ObjectDataSource Klasse anstelle der Repositoryklasse. Außerdem erstellen Sie Komponententests für die Validierungslogik. Im dritten Lernprogramm dieser Reihe fügen Sie der Anwendung Sortier- und Filterfunktionen hinzu.
Die seiten, die Sie in diesem Lernprogramm erstellen, arbeiten mit dem Departments Entitätssatz des Datenmodells zusammen, das Sie in der Lernprogrammreihe "Erste Schritte" erstellt haben.
Aktualisieren der Datenbank und des Datenmodells
Sie beginnen dieses Lernprogramm, indem Sie zwei Änderungen an der Datenbank vornehmen, die beide entsprechende Änderungen am Datenmodell erfordern, das Sie in den Lernprogrammen " Erste Schritte mit Entity Framework" und "Web Forms " erstellt haben. In einem dieser Lernprogramme haben Sie änderungen am Designer manuell vorgenommen, um das Datenmodell nach einer Datenbankänderung mit der Datenbank zu synchronisieren. In diesem Lernprogramm verwenden Sie das Tool "Aus Datenbank aktualisieren " des Designers, um das Datenmodell automatisch zu aktualisieren.
Hinzufügen einer Beziehung zur Datenbank
Öffnen Sie in Visual Studio die Contoso University-Webanwendung, die Sie in der Lernprogrammreihe "Erste Schritte mit Entity Framework" und "Web Forms " erstellt haben, und öffnen Sie dann das SchoolDiagram Datenbankdiagramm.
Wenn Sie die Department Tabelle im Datenbankdiagramm betrachten, sehen Sie, dass sie eine Administrator Spalte enthält. Diese Spalte ist ein Fremdschlüssel für die Person Tabelle, aber keine Fremdschlüsselbeziehung wird in der Datenbank definiert. Sie müssen die Beziehung erstellen und das Datenmodell aktualisieren, damit das 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.
Klicken Sie im Feld "Fremdschlüsselbeziehungen" auf "Hinzufügen", und klicken Sie dann auf die Ellipse für Tabellen- und Spaltenspezifikation.
Legen Sie im Dialogfeld "Tabellen und Spalten" die Primärschlüsseltabelle und das Primärschlüsselfeld auf Person und PersonID, und legen Sie die Fremdschlüsseltabelle und das Fremdschlüsselfeld auf Department und .Administrator (In diesem Fall ändert sich der Beziehungsname von FK_Department_Department " FK_Department_Person.")
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 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 im 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 angeben, wenn eine Datenbankeinschränkung einen Löschvorgang 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 Departments.aspx Seite, die Sie erstellen möchten, möchten Sie eine Dropdownliste von 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 aus nur den Daten, die von der Dropdownliste benötigt werden: den vollständigen Namen (richtig formatiert) und den Datensatzschlüssel.
Erweitern Sie im Server-ExplorerSchool.mdf, klicken Sie mit der rechten Maustaste auf den Ordner "Ansichten ", und wählen Sie " Neue Ansicht hinzufügen" aus.
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 als vInstructorName.
Aktualisieren des Datenmodells
Öffnen Sie im DAL-Ordner die Datei "SchoolModel.edmx ", klicken Sie mit der rechten Maustaste auf die Entwurfsoberfläche, und wählen Sie "Modell aus Datenbank aktualisieren" aus.
Wählen Sie im Dialogfeld "Datenbankobjekte auswählen" die Registerkarte "Hinzufügen" und dann die soeben erstellte Ansicht aus.
Klicken Sie auf Fertig stellen.
Im Designer sehen Sie, dass das Tool eine vInstructorName Entität und eine neue Zuordnung zwischen der Department und der Person Entität erstellt hat.
Hinweis
In den Fenstern "Ausgabe- und Fehlerliste " wird möglicherweise eine Warnmeldung angezeigt, in der Sie darüber informiert werden, dass das Tool automatisch einen Primärschlüssel für die neue vInstructorName Ansicht erstellt hat. Dieses Verhalten wird erwartet.
Wenn Sie sich im Code auf die neue vInstructorName Entität beziehen, wollen Sie nicht die Datenbankkonvention verwenden, bei der ein Kleinbuchstabe "v" vorangestellt wird. Daher benennen Sie die Entität und den Entitätensatz im Modell um.
Öffnen Sie den Modellbrowser. Sie sehen vInstructorName als Entitätstyp und Ansicht aufgelistet.
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 "Entity Set Name " in "InstructorNames".
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 werden, geben Sie das sofortige Laden dieser Eigenschaft mithilfe der Include-Methode an. Die Klasse implementiert auch die IDisposable Schnittstelle, um sicherzustellen, dass die Datenbankverbindung freigegeben wird, wenn das Objekt verworfen wird.
Hinweis
Es wird üblich, eine Repositoryklasse für jeden Entitätstyp zu erstellen. In diesem Lernprogramm 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 anstelle eines IQueryable Objekts zurück, um sicherzustellen, dass die zurückgegebene Auflistung auch nach dem Verwerfen des Repositoryobjekts verwendet werden kann. Ein IQueryable Objekt kann bei jedem Zugriff einen Datenbankzugriff verursachen, jedoch könnte das Repositoryobjekt bereits entsorgt sein, 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 dazu führen kann, dass solche Änderungen in der Datenbank beibehalten werden.
Erstellen Sie eine Departments.aspx Seite, die die Masterseite Site.Master verwendet, und fügen Sie das folgende Markup im Steuerelement mit dem Namen Content2Content hinzu.
<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 die Funktionen für automatische Datenformatierung und Validierung nutzen können. Damit diese funktionieren, müssen Sie die EnableDynamicData Methode im Page_Init Ereignishandler aufrufen. (DynamicControl Steuerelemente werden nicht im Administrator Feld verwendet, da sie nicht mit Navigationseigenschaften funktionieren.)
Die Vertical-Align="Top" Attribute werden später wichtig, wenn Sie eine Spalte mit einem geschachtelten GridView Steuerelement zum Raster 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 DAL-Ordner 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 Währung darstellt, obwohl der Datentyp lautet Decimal, und es gibt an, dass der Wert zwischen 0 und 1.000.000,000 $sein 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.
Beachten Sie, dass, obwohl Sie im Departments.aspx Seitenmarkup für die Spalten "Budget " oder " Startdatum " keine Formatzeichenfolge angegeben haben, die Standardwährungs- und Datumsformatierung von den Steuerelementen mithilfe der DynamicField Metadaten angewendet wurde, die Sie in der Department.cs Datei angegeben haben.
Hinzufügen von Einfüge- und Löschfunktionen
Öffnen Sie SchoolRepository.cs, fügen Sie den folgenden Code hinzu, um eine Insert Methode und eine Delete Methode zu erstellen. Der Code enthält auch eine Methode mit dem Namen 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 so konfiguriert ist, dass diese automatisch für die Department Tabelle berechnet wird.
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 die Verknüpfung, die im Objektstatus-Manager des Objektkontexts zwischen der Entität im Arbeitsspeicher und der datenbankzeile verwaltet wird, die sie darstellt, erneut herzustellen. Dies muss erfolgen, bevor die Methode die SaveChanges-Methode aufruft.
Der Begriff Objektkontext bezieht sich auf die Klasse des Entity Frameworks, 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 wird die Klasse benannt SchoolEntities, und eine Instanz davon wird immer benannt context. Der Objektstatus-Manager des Objektkontexts ist eine Klasse, die von der ObjectStateManager Klasse abgeleitet wird. Der Objektkontakt verwendet den Objektstatus-Manager zum Speichern von Entitätsobjekten und um nachzuverfolgen, ob jedes Objekt mit der entsprechenden Tabellenzeile oder -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 Kennzeichen so festgelegt, dass die geänderte Eigenschaft nicht mehr mit der Datenbank synchronisiert wird. Wenn Sie 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 Status der Entität und dem Status der Datenbank unterscheidet.
Dieser Vorgang funktioniert jedoch in der Regel nicht in einer Webanwendung, da die Objektkontextinstanz, die eine Entität liest, zusammen mit allem im Objektstatus-Manager gelöscht wird, nachdem eine Seite gerendert wurde. Die Objektkontextinstanz, die Änderungen anwenden muss, ist eine neue Instanz, die für die Postbackverarbeitung instanziiert wird. Im Fall der DeleteDepartment Methode erstellt das ObjectDataSource Steuerelement erneut die ursprüngliche Version der Entität für Sie aus Werten im Ansichtszustand, aber diese neu erstellte Department Entität ist im Objektstatus-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 Aufrufen der Attach Methode wird jedoch die gleiche Nachverfolgung zwischen der neu erstellten Entität und den Werten in der Datenbank hergestellt, die ursprünglich automatisch ausgeführt wurde, als die Entität in einer früheren Instanz des Objektkontexts gelesen wurde.
Es gibt Situationen, 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 finden Sie in späteren Lernprogrammen in dieser Reihe.
Die SaveChanges-Methode
Diese einfache Repositoryklasse veranschaulicht die Grundprinzipien der Durchführung von CRUD-Vorgängen. In diesem Beispiel wird die SaveChanges Methode unmittelbar nach jeder Aktualisierung aufgerufen. In einer Produktionsanwendung möchten Sie die SaveChanges Methode möglicherweise von einer separaten Methode aufrufen, um Ihnen mehr Kontrolle darüber zu geben, wann die Datenbank aktualisiert wird. (Am Ende des nächsten Lernprogramms finden Sie einen Link zu einem Whitepaper, das die Einheit des Arbeitsmusters erläutert, bei der es sich um einen Ansatz zur Koordinierung verwandter Updates handelt.) Beachten Sie auch, dass die DeleteDepartment Methode im Beispiel keinen Code für die Behandlung von Parallelitätskonflikten enthält. Code, der in einem späteren Lernprogramm dieser Reihe hinzugefügt wird.
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 den folgenden Code in \
public IEnumerable<InstructorName> GetInstructorNames()
{
return context.InstructorNames.OrderBy("it.FullName").ToList();
}
Erstellen einer Seite für das Einfügen von Abteilungen
Erstellen Sie eine DepartmentsAdd.aspx Seite, die die Seite "Site.Master " verwendet, und fügen Sie das folgende Markup im Steuerelement mit dem Content Namen hinzu Content2:
<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 für die Eingabe neuer Abteilungen und gibt einen Handler für das Steuerelementereignis ItemInserting an, sodass Sie den Administrator Fremdschlüsselwert festlegen können. Am Ende ist 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 folgende Klassenvariable 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 ermöglicht dynamische Datenfunktionen. Der Handler für das DropDownList Steuerelementereignis speichert einen Verweis auf das Steuerelement, und der Handler für das Init Steuerelementereignis DetailsView verwendet diesen Verweis, um den Inserting Wert des ausgewählten Kursleiters PersonID 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 ".
Geben Sie Werte für eine andere neue Abteilung ein. Geben Sie eine Zahl größer als 1.000.000,00 in das Feld "Budget" ein und wechseln Sie mit der Tabulatortaste zum nächsten Feld. Ein Sternchen wird im Feld angezeigt, und wenn Sie den Mauszeiger darauf halten, wird die Fehlermeldung angezeigt, die Sie in die Metadaten für dieses Feld eingegeben haben.
Klicken Sie auf "Einfügen", und Sie sehen die Fehlermeldung, die vom ValidationSummary Steuerelement unten auf der Seite angezeigt wird.
Schließen Sie als Nächstes den Browser, und öffnen Sie die Departments.aspx Seite. Fügen Sie der Departments.aspx Seite die Löschfunktion hinzu, indem Sie dem DeleteMethod Steuerelement ein ObjectDataSource Attribut und ein DataKeyNames Attribut für das GridView Steuerelement 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" >
Laden Sie die Seite.
Löschen Sie die Abteilung, die Sie hinzugefügt haben, wenn Sie die DepartmentsAdd.aspx Seite ausgeführt 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. Eine enthält die ursprünglichen Werte, die im Ansichtszustand gespeichert wurden, und die andere enthält die neuen Werte, die in das GridView Steuerelement eingegeben wurden. Der Code in der UpdateDepartment Methode übergibt die Department Entität mit den ursprünglichen Werten 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 mit den neuen Werten 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 Aktualisierungsfunktion für diese Entität jedoch einer gespeicherten Prozedur zugeordnet wurde, wird die gesamte Zeile unabhängig davon aktualisiert, welche Spalten geändert wurden.)
Öffnen Sie die datei Departments.aspx , und fügen Sie dem DepartmentsObjectDataSource Steuerelement die folgenden Attribute hinzu:
UpdateMethod="UpdateDepartment"ConflictDetection="CompareAllValues"
Dies bewirkt, dass alte Werte im Ansichtszustand gespeichert werden, sodass sie mit den neuen Werten in derUpdateMethode verglichen werden können.OldValuesParameterFormatString="orig{0}"
Dadurch wird das Steuerelement darüber informiert, dass der Name des ursprünglichen Werteparameters lautetorigDepartment.
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 OnRowUpdating="DepartmentsGridView_RowUpdating" Steuerelement ein GridView 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 ein EditItemTemplate Steuerelement für die Administrator Spalte zum GridView Steuerelement hinzu, unmittelbar nach dem ItemTemplate Steuerelement für diese Spalte.
<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 SelectedValue des Attributs festgelegt wird.
Fügen Sie vor dem GridView Steuerelement ein ValidationSummary Steuerelement wie auf der seite DepartmentsAdd.aspx 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, um auf das DropDownList Steuerelement zu verweisen:
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 Wert abzurufen, den der Benutzer eingegeben hat, und wendet ihn auf die Administrator Eigenschaft der Department Entität an.
Verwenden Sie die DepartmentsAdd.aspx Seite, um eine neue Abteilung hinzuzufügen, führen Sie dann die Departments.aspx Seite aus, und klicken Sie auf "Bearbeiten" in der Zeile, die Sie hinzugefügt haben.
Hinweis
Sie können keine Zeilen bearbeiten, die Sie nicht hinzugefügt haben (d. a. dies war bereits in der Datenbank), weil ungültige Daten in der Datenbank vorhanden sind; Die Administratoren für die Zeilen, die mit der Datenbank erstellt wurden, sind Kursteilnehmer. 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.
Wenn Sie einen ungültigen Budgetbetrag eingeben und dann auf "Aktualisieren" klicken, wird das gleiche Sternchen und dieselbe 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.
Damit wird die Einführung in die Verwendung des ObjectDataSource Steuerelements für grundlegende CRUD-Vorgänge (Erstellen, Lesen, Aktualisieren, Löschen) mit Entity Framework abgeschlossen. Sie haben eine einfache n-Ebene-Anwendung erstellt, aber die Geschäftslogikebene ist immer noch eng mit der Datenzugriffsschicht gekoppelt, wodurch automatisierte Komponententests erschwert werden. Im folgenden Lernprogramm erfahren Sie, wie Sie das Repositorymuster implementieren, um Komponententests zu erleichtern.