Erweiterte Entity Framework-Szenarien für eine MVC-Webanwendung (10 von 10)

von Tom Dykstra

Die Contoso University-Beispielwebanwendung veranschaulicht, wie sie ASP.NET MVC 4-Anwendungen mithilfe von Entity Framework 5 Code First und Visual Studio 2012 erstellen. Informationen zu dieser Tutorialreihe finden Sie im ersten Tutorial der Reihe.

Hinweis

Wenn ein Problem auftritt, das Sie nicht beheben können, laden Sie das abgeschlossene Kapitel herunter , und versuchen Sie, das Problem zu reproduzieren. Im Allgemeinen können Sie die Lösung für das Problem finden, indem Sie Ihren Code mit dem abgeschlossenen Code vergleichen. Einige häufige Fehler und deren Behebung finden Sie unter Fehler und Problemumgehungen.

Im vorherigen Tutorial haben Sie das Repository und die Arbeitseinheitsmuster implementiert. Dieses Tutorial behandelt die folgenden Themen:

  • Ausführen von unformatierten SQL-Abfragen.
  • Ausführen von Abfragen ohne Nachverfolgung.
  • Untersuchen von Abfragen, die an die Datenbank gesendet werden.
  • Arbeiten mit Proxyklassen.
  • Deaktivieren der automatischen Erkennung von Änderungen.
  • Deaktivieren der Überprüfung beim Speichern von Änderungen.
  • Fehler und Problembehandlungen

Für die meisten dieser Themen arbeiten Sie mit Seiten, die Sie bereits erstellt haben. Um SQL-Rohdaten für Massenupdates zu verwenden, erstellen Sie eine neue Seite, auf der die Anzahl der Guthaben aller Kurse in der Datenbank aktualisiert wird:

Screenshot: Seite

Um eine Abfrage ohne Nachverfolgung zu verwenden, fügen Sie der Seite Abteilungsbearbeitung eine neue Validierungslogik hinzu:

Screenshot: Seite

Ausführen von SQL-Rohabfragen

Die Entity Framework Code First-API enthält Methoden, mit denen Sie SQL-Befehle direkt an die Datenbank übergeben können. Sie haben folgende Optionen:

  • Verwenden Sie die DbSet.SqlQuery-Methode für Abfragen, die Entitätstypen zurückgeben. Die zurückgegebenen Objekte müssen vom Typ sein, der DbSet vom Objekt erwartet wird, und sie werden automatisch vom Datenbankkontext nachverfolgt, es sei denn, Sie deaktivieren die Nachverfolgung. (Weitere Informationen zur -Methode finden Sie im folgenden Abschnitt AsNoTracking .)
  • Verwenden Sie die Database.SqlQuery -Methode für Abfragen, die Typen zurückgeben, die keine Entitäten sind. Die zurückgegebenen Daten werden nicht vom Datenbankkontext nachverfolgt, auch wenn Sie diese Methode zum Abrufen von Entitätstypen verwenden.
  • Verwenden Sie den Database.ExecuteSqlCommand für Nicht-Abfragebefehle.

Einer der Vorteile von Entity Framework ist die Tatsache, dass vermieden wird, den Code zu eng an eine bestimmte Methode zum Speichern von Daten zu binden. Dies geschieht, indem SQL-Abfragen und -Befehle für Sie generiert werden. Somit müssen Sie sie nicht selbst schreiben. Es gibt jedoch außergewöhnliche Szenarien, in denen Sie bestimmte SQL-Abfragen ausführen müssen, die Sie manuell erstellt haben, und diese Methoden ermöglichen es Ihnen, solche Ausnahmen zu behandeln.

Dies trifft immer zu, wenn Sie SQL-Befehle in einer Webanwendung ausführen. Treffen Sie deshalb Vorsichtsmaßnahmen, um Ihre Website vor Angriffen durch Einschleusung von SQL-Befehlen zu schützen. Verwenden Sie dazu parametrisierte Abfragen, um sicherzustellen, dass Zeichenfolgen, die von einer Webseite übermittelt werden, nicht als SQL-Befehle interpretiert werden können. In diesem Tutorial verwenden Sie parametrisierte Abfragen beim Integrieren von Benutzereingaben in eine Abfrage.

Aufrufen einer Abfrage, die Entitäten zurückgibt

Angenommen, Sie möchten, dass die GenericRepository Klasse zusätzliche Filter- und Sortierflexibilität bietet, ohne dass Sie eine abgeleitete Klasse mit zusätzlichen Methoden erstellen müssen. Eine Möglichkeit, dies zu erreichen, wäre das Hinzufügen einer Methode, die eine SQL-Abfrage akzeptiert. Sie können dann eine beliebige Filterung oder Sortierung im Controller angeben, z. B. eine Where Klausel, die von einem Join oder einer Unterabfrage abhängt. In diesem Abschnitt erfahren Sie, wie Sie eine solche Methode implementieren.

Erstellen Sie die GetWithRawSql -Methode, indem Sie den folgenden Code zu GenericRepository.cs hinzufügen:

public virtual IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters)
{
    return dbSet.SqlQuery(query, parameters).ToList();
}

Rufen Sie in CourseController.cs die neue Methode aus der Details -Methode auf, wie im folgenden Beispiel gezeigt:

public ActionResult Details(int id)
{
    var query = "SELECT * FROM Course WHERE CourseID = @p0";
    return View(unitOfWork.CourseRepository.GetWithRawSql(query, id).Single());
}

In diesem Fall hätten Sie die GetByID -Methode verwenden können, aber Sie verwenden die GetWithRawSql -Methode, um zu überprüfen, ob die GetWithRawSQL Methode funktioniert.

Führen Sie die Seite Details aus, um zu überprüfen, ob die Auswahlabfrage funktioniert (wählen Sie die Registerkarte Kurs und dann Details für einen Kurs aus).

Screenshot der Seite

Aufrufen einer Abfrage, die andere Objekttypen zurückgibt

Sie haben zuvor ein Statistikraster für Studenten für die Infoseite erstellt, das die Anzahl der Studenten für jedes Anmeldedatum zeigt. Der Code, der dies in "HomeController.cs " ausführt, verwendet LINQ:

var data = from student in db.Students
           group student by student.EnrollmentDate into dateGroup
           select new EnrollmentDateGroup()
           {
               EnrollmentDate = dateGroup.Key,
               StudentCount = dateGroup.Count()
           };

Angenommen, Sie möchten den Code schreiben, der diese Daten direkt in SQL abruft, anstatt LINQ zu verwenden. Dazu müssen Sie eine Abfrage ausführen, die etwas anderes als Entitätsobjekte zurückgibt. Dies bedeutet, dass Sie die Database.SqlQuery -Methode verwenden müssen.

Ersetzen Sie in HomeController.cs die LINQ-Anweisung in der About -Methode durch den folgenden Code:

var query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
    + "FROM Person "
    + "WHERE EnrollmentDate IS NOT NULL "
    + "GROUP BY EnrollmentDate";
var data = db.Database.SqlQuery<EnrollmentDateGroup>(query);

Führen Sie die Seite Info aus. Sie zeigt die gleichen Daten wie zuvor.

Screenshot der Seite

Aufrufen einer Updateabfrage

Angenommen, Administratoren der Contoso University möchten massenweise Änderungen in der Datenbank durchführen können, z. B. die Anzahl der Credits für jeden Kurs ändern. Wenn die Universität über eine große Anzahl an Kursen verfügt, wäre es ineffizient, sie alle als Entitäten abzurufen und separat zu ändern. In diesem Abschnitt implementieren Sie eine Webseite, auf der der Benutzer einen Faktor angeben kann, um den die Anzahl der Guthaben für alle Kurse ändern kann, und Sie nehmen die Änderung durch Ausführen einer SQL-Anweisung UPDATE vor. Die Webseite wird wie die folgende Abbildung aussehen:

Screenshot: Seite

Im vorherigen Tutorial haben Sie das generische Repository verwendet, um Entitäten im Course Controller zu lesen und zu aktualisierenCourse. Für diesen Massenupdatevorgang müssen Sie eine neue Repositorymethode erstellen, die sich nicht im generischen Repository befindet. Zu diesem Zweck erstellen Sie eine dedizierte CourseRepository Klasse, die von der GenericRepository -Klasse abgeleitet wird.

Erstellen Sie im Ordner DALcourseRepository.cs , und ersetzen Sie den vorhandenen Code durch den folgenden Code:

using System;
using ContosoUniversity.Models;

namespace ContosoUniversity.DAL
{
    public class CourseRepository : GenericRepository<Course>
    {
        public CourseRepository(SchoolContext context)
            : base(context)
        {
        }

        public int UpdateCourseCredits(int multiplier)
        {
            return context.Database.ExecuteSqlCommand("UPDATE Course SET Credits = Credits * {0}", multiplier);
        }

    }
}

Ändern Sie in UnitOfWork.cs den Course Repositorytyp von in GenericRepository<Course>CourseRepository:

private CourseRepository courseRepository;
public CourseRepository CourseRepository
{
    get
    {

        if (this.courseRepository == null)
        {
            this.courseRepository = new CourseRepository(context);
        }
        return courseRepository;
    }
}

Fügen Sie in CourseController.cs eine Methode hinzu UpdateCourseCredits :

public ActionResult UpdateCourseCredits(int? multiplier)
{
    if (multiplier != null)
    {
        ViewBag.RowsAffected = unitOfWork.CourseRepository.UpdateCourseCredits(multiplier.Value);
    }
    return View();
}

Diese Methode wird sowohl für als auch HttpGetHttpPostverwendet. Wenn die HttpGetUpdateCourseCredits Methode ausgeführt wird, ist die multiplier Variable NULL, und die Ansicht zeigt ein leeres Textfeld und eine Schaltfläche zum Senden an, wie in der vorherigen Abbildung gezeigt.

Wenn auf die Schaltfläche Aktualisieren geklickt wird und die HttpPost Methode ausgeführt wird, multiplier wird der Wert in das Textfeld eingegeben. Der Code ruft dann die Repositorymethode UpdateCourseCredits auf, die die Anzahl der betroffenen Zeilen zurückgibt, und dieser Wert wird im ViewBag -Objekt gespeichert. Wenn die Ansicht die Anzahl der betroffenen Zeilen im ViewBag Objekt empfängt, wird diese Zahl anstelle des Textfelds und der Schaltfläche "Senden" angezeigt, wie in der folgenden Abbildung gezeigt:

Screenshot: Seite

Erstellen Sie eine Ansicht im Ordner Views\Course für die Seite Kursguthaben aktualisieren:

Screenshot: Dialogfeld

Ersetzen Sie in Views\Course\UpdateCourseCredits.cshtml den Vorlagencode durch den folgenden Code:

@model ContosoUniversity.Models.Course

@{
    ViewBag.Title = "UpdateCourseCredits";
}

<h2>Update Course Credits</h2>

@if (ViewBag.RowsAffected == null)
{
    using (Html.BeginForm())
    {
        <p>
            Enter a number to multiply every course's credits by: @Html.TextBox("multiplier")
        </p>
        <p>
            <input type="submit" value="Update" />
        </p>
    }
}
@if (ViewBag.RowsAffected != null)
{
    <p>
        Number of rows updated: @ViewBag.RowsAffected
    </p>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Führen Sie die UpdateCourseCredits-Methode aus, indem Sie die Registerkarte Courses (Kurse) auswählen, und dann „/UpdateCourseCredits“ am Ende der URL in die Adressleiste des Browsers einfügen (z.B.: http://localhost:50205/Course/UpdateCourseCredits). Geben Sie eine Zahl in das Textfeld ein:

Screenshot: Seite

Klicken Sie auf Aktualisieren. Die Anzahl der betroffenen Zeilen wird angezeigt:

Screenshot: Seite

Klicken Sie auf Zurück zur Liste, um die Kursliste mit der geänderte Anzahl von Credits anzuzeigen.

Screenshot: Seite

Weitere Informationen zu unformatierten SQL-Abfragen finden Sie unter Raw SQL-Abfragen im Entity Framework-Teamblog.

Abfragen ohne Nachverfolgung

Wenn ein Datenbankkontext Datenbankzeilen abruft und Entitätsobjekte erstellt, die diese darstellen, wird standardmäßig nachverfolgt, ob die Entitäten im Arbeitsspeicher mit den In der Datenbank synchronisiert sind. Die Daten im Arbeitsspeicher fungieren als Cache und werden verwendet, wenn Sie eine Entität aktualisieren. Diese Zwischenspeicherung ist in Webanwendungen oft überflüssig, da Kontextinstanzen in der Regel kurzlebig sind (eine neue wird bei jeder Anforderung erstellt und gelöscht), und der Kontext, der eine Entität liest, wird in der Regel gelöscht, bevor diese Entität erneut verwendet wird.

Sie können angeben, ob der Kontext Entitätsobjekte für eine Abfrage nachverfolgt, indem Sie die AsNoTracking -Methode verwenden. Typische Szenarios, in denen Sie das möglicherweise tun wollen, umfassen Folgendes:

  • Die Abfrage ruft eine so große Datenmenge ab, dass das Deaktivieren der Nachverfolgung die Leistung spürbar verbessern kann.
  • Sie möchten eine Entität anfügen, um sie zu aktualisieren, aber Sie haben zuvor dieselbe Entität für einen anderen Zweck abgerufen. Da diese Entität bereits vom Datenbankkontext nachverfolgt wird, können Sie die zu ändernde Entität nicht anfügen. Eine Möglichkeit, dies zu verhindern, ist die Verwendung der AsNoTracking Option mit der früheren Abfrage.

In diesem Abschnitt implementieren Sie Geschäftslogik, die das zweite dieser Szenarien veranschaulicht. Insbesondere erzwingen Sie eine Geschäftsregel, die besagt, dass ein Dozent nicht der Administrator mehrerer Abteilungen sein kann.

Fügen Sie in DepartmentController.cs eine neue Methode hinzu, die Sie über die Edit Methoden und Create aufrufen können, um sicherzustellen, dass keine zwei Abteilungen über denselben Administrator verfügen:

private void ValidateOneAdministratorAssignmentPerInstructor(Department department)
{
    if (department.PersonID != null)
    {
        var duplicateDepartment = db.Departments
            .Include("Administrator")
            .Where(d => d.PersonID == department.PersonID)
            .FirstOrDefault();
        if (duplicateDepartment != null && duplicateDepartment.DepartmentID != department.DepartmentID)
        {
            var errorMessage = String.Format(
                "Instructor {0} {1} is already administrator of the {2} department.",
                duplicateDepartment.Administrator.FirstMidName,
                duplicateDepartment.Administrator.LastName,
                duplicateDepartment.Name);
            ModelState.AddModelError(string.Empty, errorMessage);
        }
    }
}

Fügen Sie Code try im Block der HttpPostEdit -Methode hinzu, um diese neue Methode aufzurufen, wenn keine Validierungsfehler vorliegen. Der try Block sieht nun wie im folgenden Beispiel aus:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
   [Bind(Include = "DepartmentID, Name, Budget, StartDate, RowVersion, PersonID")]
    Department department)
{
   try
   {
      if (ModelState.IsValid)
      {
         ValidateOneAdministratorAssignmentPerInstructor(department);
      }

      if (ModelState.IsValid)
      {
         db.Entry(department).State = EntityState.Modified;
         db.SaveChanges();
         return RedirectToAction("Index");
      }
   }
   catch (DbUpdateConcurrencyException ex)
   {
      var entry = ex.Entries.Single();
      var clientValues = (Department)entry.Entity;

Führen Sie die Seite Abteilung bearbeiten aus, und versuchen Sie, den Administrator einer Abteilung in einen Dozenten zu ändern, der bereits der Administrator einer anderen Abteilung ist. Sie erhalten die erwartete Fehlermeldung:

Screenshot der Seite

Führen Sie nun die Seite "Abteilung bearbeiten" erneut aus, und ändern Sie dieses Mal den Budgetbetrag . Wenn Sie auf Speichern klicken, wird eine Fehlerseite angezeigt:

Screenshot: Seite

Die Ausnahmefehlermeldung lautet "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key." Dies ist aufgrund der folgenden Abfolge von Ereignissen aufgetreten:

  • Die Edit -Methode ruft die ValidateOneAdministratorAssignmentPerInstructor -Methode auf, die alle Abteilungen abruft, die Kim Abercrombie als Administrator haben. Dies bewirkt, dass die englische Abteilung gelesen wird. Da dies die Abteilung ist, die bearbeitet wird, wird kein Fehler gemeldet. Als Ergebnis dieses Lesevorgangs wird die englische Abteilungsentität, die aus der Datenbank gelesen wurde, jetzt vom Datenbankkontext nachverfolgt.
  • Die Edit -Methode versucht, das Flag für die Modified englische Abteilungsentität festzulegen, die von der MVC-Modellbindung erstellt wurde. Dies schlägt jedoch fehl, da der Kontext bereits eine Entität für die englische Abteilung nachverfolgt.

Eine Lösung für dieses Problem besteht darin, den Kontext daran zu hindern, von der Überprüfungsabfrage abgerufene In-Memory-Abteilungsentitäten zu verfolgen. Dies hat keinen Nachteil, da Sie diese Entität nicht aktualisieren oder in einer Weise erneut lesen, die davon profitieren würde, dass sie im Arbeitsspeicher zwischengespeichert wird.

Geben Sie in DepartmentController.cs in der ValidateOneAdministratorAssignmentPerInstructor -Methode keine Nachverfolgung an, wie im Folgenden gezeigt:

var duplicateDepartment = db.Departments
   .Include("Administrator")
   .Where(d => d.PersonID == department.PersonID)
   .AsNoTracking()
   .FirstOrDefault();

Wiederholen Sie den Versuch, den Budgetbetrag einer Abteilung zu bearbeiten. Dieses Mal ist der Vorgang erfolgreich, und die Website kehrt wie erwartet zur Seite Abteilungsindex zurück, auf der der überarbeitete Budgetwert angezeigt wird.

Untersuchen von Abfragen, die an die Datenbank gesendet werden

Manchmal ist es hilfreich, die tatsächlichen SQL-Abfragen anzuzeigen, die an die Datenbank gesendet werden. Dazu können Sie eine Abfragevariable im Debugger untersuchen oder die -Methode der Abfrage ToString aufrufen. Um dies auszuprobieren, sehen Sie sich eine einfache Abfrage an und sehen sich dann an, was damit geschieht, während Sie Optionen wie eifrig laden, filtern und sortieren hinzufügen.

Ersetzen Sie in Controllers/CourseController die Index -Methode durch den folgenden Code:

public ViewResult Index()
{
    var courses = unitOfWork.CourseRepository.Get();
    return View(courses.ToList());
}

Legen Sie nun einen Haltepunkt in GenericRepository.cs für die return query.ToList(); - und - return orderBy(query).ToList(); Anweisungen der Get -Methode fest. Führen Sie das Projekt im Debugmodus aus, und wählen Sie die Seite Kursindex aus. Wenn der Code den Haltepunkt erreicht, untersuchen Sie die query Variable. Sie sehen die Abfrage, die an SQL Server gesendet wird. Es handelt sich um eine einfache Select Anweisung:

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID]
FROM [Course] AS [Extent1]}

Screenshot: Registerkarte

Abfragen können zu lang sein, um sie in den Debugfenstern in Visual Studio anzuzeigen. Um die gesamte Abfrage anzuzeigen, können Sie den Variablenwert kopieren und in einen Text-Editor einfügen:

Screenshot, der den Variablenwert mit einem Dropdownmenü zeigt, das angezeigt wird, wenn er ausgewählt wird. Die Option Wert kopieren ist hervorgehoben.

Nun fügen Sie der Seite Kursindex eine Dropdownliste hinzu, damit Benutzer nach einer bestimmten Abteilung filtern können. Sie sortieren die Kurse nach Titel, und Sie geben eager loading für die Department Navigationseigenschaft an. Ersetzen Sie in CourseController.cs die Index -Methode durch den folgenden Code:

public ActionResult Index(int? SelectedDepartment)
{
    var departments = unitOfWork.DepartmentRepository.Get(
        orderBy: q => q.OrderBy(d => d.Name));
    ViewBag.SelectedDepartment = new SelectList(departments, "DepartmentID", "Name", SelectedDepartment);

    int departmentID = SelectedDepartment.GetValueOrDefault(); 
    return View(unitOfWork.CourseRepository.Get(
        filter: d => !SelectedDepartment.HasValue || d.DepartmentID == departmentID,
        orderBy: q => q.OrderBy(d => d.CourseID),
        includeProperties: "Department"));
}

Die -Methode empfängt den ausgewählten Wert der Dropdownliste im SelectedDepartment Parameter. Wenn nichts ausgewählt ist, ist dieser Parameter NULL.

Eine SelectList Auflistung, die alle Abteilungen enthält, wird an die Ansicht für die Dropdownliste übergeben. Die an den SelectList Konstruktor übergebenen Parameter geben den Wertfeldnamen, den Namen des Textfelds und das ausgewählte Element an.

Für die Get -Methode des Course Repositorys gibt der Code einen Filterausdruck, eine Sortierreihenfolge und eager loading für die Department Navigationseigenschaft an. Der Filterausdruck gibt immer dann zurück true , SelectedDepartment wenn in der Dropdownliste nichts ausgewählt ist (d. a. ist NULL).

Fügen Sie in Views\Course\Index.cshtml unmittelbar vor dem öffnenden table Tag den folgenden Code hinzu, um die Dropdownliste und eine Schaltfläche zum Senden zu erstellen:

@using (Html.BeginForm())
{
    <p>Select Department: @Html.DropDownList("SelectedDepartment","All")   
    <input type="submit" value="Filter" /></p>
}

Wenn die Haltepunkte in der GenericRepository Klasse noch festgelegt sind, führen Sie die Seite Kursindex aus. Fahren Sie durch die ersten beiden Male, bei denen der Code auf einen Haltepunkt trifft, damit die Seite im Browser angezeigt wird. Wählen Sie in der Dropdownliste eine Abteilung aus, und klicken Sie auf Filtern:

Screenshot: Seite

Diesmal ist der erste Haltepunkt für die Abteilungsabfrage für die Dropdownliste. Überspringen Sie dies, und zeigen Sie die query Variable an, wenn der Code das nächste Mal den Haltepunkt erreicht, um zu sehen, wie die Course Abfrage jetzt aussieht. Es wird etwa folgendes angezeigt:

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID], 
[Extent2].[DepartmentID] AS [DepartmentID1], 
[Extent2].[Name] AS [Name], 
[Extent2].[Budget] AS [Budget], 
[Extent2].[StartDate] AS [StartDate], 
[Extent2].[PersonID] AS [PersonID], 
[Extent2].[Timestamp] AS [Timestamp]
FROM  [Course] AS [Extent1]
INNER JOIN [Department] AS [Extent2] ON [Extent1].[DepartmentID] = [Extent2].[DepartmentID]
WHERE (@p__linq__0 IS NULL) OR ([Extent1].[DepartmentID] = @p__linq__1)}

Sie können sehen, dass die Abfrage jetzt eine JOIN Abfrage ist, die Daten zusammen mit den Course Daten lädtDepartment, und dass sie eine WHERE -Klausel enthält.

Arbeiten mit Proxyklassen

Wenn Entity Framework Entitätsinstanzen erstellt (z. B. wenn Sie eine Abfrage ausführen), werden diese häufig als Instanzen eines dynamisch generierten abgeleiteten Typs erstellt, der als Proxy für die Entität fungiert. Dieser Proxy überschreibt einige virtuelle Eigenschaften der Entität, um Hooks zum automatischen Ausführen von Aktionen einzufügen, wenn auf die Eigenschaft zugegriffen wird. Dieser Mechanismus wird beispielsweise verwendet, um das verzögerte Laden von Beziehungen zu unterstützen.

In den meisten Fällen müssen Sie diese Verwendung von Proxys nicht kennen, aber es gibt Ausnahmen:

  • In einigen Szenarien möchten Sie möglicherweise verhindern, dass Entity Framework Proxyinstanzen erstellt. Beispielsweise kann das Serialisieren von Nicht-Proxyinstanzen effizienter sein als das Serialisieren von Proxyinstanzen.
  • Wenn Sie eine Entitätsklasse mithilfe des new Operators instanziieren, erhalten Sie keinen Proxy instance. Dies bedeutet, dass Sie keine Funktionen wie verzögertes Laden und automatische Änderungsnachverfolgung erhalten. Dies ist in der Regel in Ordnung. Sie benötigen im Allgemeinen kein verzögertes Laden, da Sie eine neue Entität erstellen, die sich nicht in der Datenbank befindet, und Sie benötigen im Allgemeinen keine Änderungsnachverfolgung, wenn Sie die Entität explizit als Addedmarkieren. Wenn Sie jedoch verzögertes Laden benötigen und Änderungsnachverfolgung benötigen, können Sie mithilfe der Create -Methode der DbSet -Klasse neue Entitätsinstanzen mit Proxys erstellen.
  • Möglicherweise möchten Sie einen tatsächlichen Entitätstyp aus einem Proxytyp abrufen. Sie können die GetObjectType -Methode der ObjectContext -Klasse verwenden, um den tatsächlichen Entitätstyp eines Proxytyps instance abzurufen.

Weitere Informationen finden Sie unter Arbeiten mit Proxys im Entity Framework-Teamblog.

Deaktivieren der automatischen Erkennung von Änderungen

Entity Framework bestimmt wie eine Entität geändert wurde (und welche Updates an die Datenbank gesendet werden müssen), indem die aktuellen Werte einer Entität mit den ursprünglichen Werten verglichen werden. Die ursprünglichen Werte werden gespeichert, wenn die Entität abgefragt oder angefügt wurde. Einige der Methoden, die automatisch eine Änderungserkennung durchführen, sind die folgenden:

  • DbSet.Find
  • DbSet.Local
  • DbSet.Remove
  • DbSet.Add
  • DbSet.Attach
  • DbContext.SaveChanges
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries

Wenn Sie eine große Anzahl von Entitäten nachverfolgen und eine dieser Methoden mehrmals in einer Schleife aufrufen, erhalten Sie möglicherweise erhebliche Leistungsverbesserungen, indem Sie die automatische Änderungserkennung vorübergehend mithilfe der AutoDetectChangesEnabled-Eigenschaft deaktivieren. Weitere Informationen finden Sie unter Automatisches Erkennen von Änderungen.

Deaktivieren der Überprüfung beim Speichern von Änderungen

Wenn Sie die SaveChanges -Methode aufrufen, überprüft Entity Framework standardmäßig die Daten in allen Eigenschaften aller geänderten Entitäten, bevor die Datenbank aktualisiert wird. Wenn Sie eine große Anzahl von Entitäten aktualisiert und die Daten bereits überprüft haben, ist diese Arbeit unnötig, und Sie können den Prozess zum Speichern der Änderungen in Anspruch nehmen, indem Sie die Überprüfung vorübergehend deaktivieren. Dazu können Sie die ValidateOnSaveEnabled-Eigenschaft verwenden. Weitere Informationen finden Sie unter Validierung.

Zusammenfassung

Dadurch wird diese Reihe von Tutorials zur Verwendung von Entity Framework in einer ASP.NET MVC-Anwendung abgeschlossen. Links zu anderen Entity Framework-Ressourcen finden Sie im ASP.NET Data Access Content Map.

Weitere Informationen zum Bereitstellen Ihrer Webanwendung, nachdem Sie sie erstellt haben, finden Sie unter ASP.NET Bereitstellungsinhaltszuordnung in der MSDN Library.

Informationen zu anderen Themen im Zusammenhang mit MVC, z. B. Authentifizierung und Autorisierung, finden Sie in den empfohlenen MVC-Ressourcen.

Danksagungen

  • Tom Dykstra hat die originale Version dieses Tutorials geschrieben und ist senior Programming Writer im Microsoft Web Platform and Tools Content Team.
  • Rick Anderson (twitter @RickAndMSFT) hat dieses Tutorial mitverfasst und den größten Teil der Aktualisierung für EF 5 und MVC 4 ausgeführt. Rick ist senior programming writer für Microsoft mit Schwerpunkt auf Azure und MVC.
  • Rowan Miller und andere Mitglieder des Entity Framework-Teams halfen bei code reviews und halfen beim Debuggen vieler Probleme mit Migrationen, die beim Aktualisieren des Tutorials für EF 5 aufgetreten sind.

VB

Als das Tutorial ursprünglich erstellt wurde, haben wir sowohl C#- als auch VB-Versionen des abgeschlossenen Downloadprojekts bereitgestellt. Mit diesem Update stellen wir ein herunterladbares C#-Projekt für jedes Kapitel bereit, um den Einstieg überall in der Reihe zu erleichtern, aber aufgrund von Zeitbeschränkungen und anderen Prioritäten haben wir dies für VB nicht getan. Wenn Sie mithilfe dieser Tutorials ein VB-Projekt erstellen und bereit wären, dies mit anderen zu teilen, teilen Sie uns dies bitte mit.

Fehler und Problemumgehungen

Erstellen/Schattenkopie nicht

Fehlermeldung:

"DotNetOpenAuth.OpenId" kann nicht erstellt/kopiert werden, wenn diese Datei bereits vorhanden ist.

Lösung:

Warten Sie einige Sekunden, und aktualisieren Sie die Seite.

Update-Database nicht erkannt

Fehlermeldung:

Der Begriff "Update-Database" wird nicht als Name eines Cmdlets, einer Funktion, einer Skriptdatei oder eines bedienbaren Programms erkannt. Prüfen Sie die Schreibweise des Namens bzw. stellen Sie sicher, dass der Pfad korrekt angegeben wurde, und versuchen Sie es erneut.(Aus dem Update-Database Befehl im PMC.)

Lösung:

Beenden Sie Visual Studio. Öffnen Sie das Projekt erneut, und versuchen Sie es erneut.

Fehler bei der Überprüfung

Fehlermeldung:

Fehler bei der Überprüfung für mindestens eine Entität. Weitere Informationen finden Sie unter "EntityValidationErrors"-Eigenschaft. (Aus dem Update-Database Befehl im PMC.)

Lösung:

Eine Ursache für dieses Problem sind Validierungsfehler, wenn die Seed Methode ausgeführt wird. Tipps zum Debuggen der Seed Methode finden Sie unter Seeding and Debugging Entity Framework (EF)-DBs.

HTTP 500.19-Fehler

Fehlermeldung:

HTTP-Fehler 500.19: Interner Serverfehler
Auf die angeforderte Seite kann nicht zugegriffen werden, da die zugehörigen Konfigurationsdaten für die Seite ungültig sind.

Lösung:

Eine Möglichkeit, diesen Fehler zu erhalten, besteht darin, mehrere Kopien der Lösung zu haben, von denen jede die gleiche Portnummer verwendet. Sie können dieses Problem in der Regel lösen, indem Sie alle Instanzen von Visual Studio beenden und dann das Projekt neu starten, an dem Sie arbeiten. Wenn dies nicht funktioniert, versuchen Sie, die Portnummer zu ändern. Klicken Sie mit der rechten Maustaste auf die Projektdatei, und klicken Sie dann auf Eigenschaften. Wählen Sie die Registerkarte Web aus, und ändern Sie dann die Portnummer im Textfeld Projekt-URL .

Fehler beim Bestimmen der SQL Server-Instanz

Fehlermeldung:

Ein netzwerkbezogener oder instanzspezifischer Fehler beim Herstellen einer Verbindung mit SQL Server. Der Server wurde nicht gefunden, oder auf ihn kann nicht zugegriffen werden. Stellen Sie sicher, dass der Instanzname richtig und SQL Server so konfiguriert ist, das Remoteverbindungen zulässig sind. (Anbieter: SQL-Netzwerkschnittstellen, Fehler: 26: Fehler beim Suchen des angegebenen Servers/der angegebenen Instanz)

Projektmappe:

Überprüfen Sie die Verbindungszeichenfolge. Wenn Sie die Datenbank manuell gelöscht haben, ändern Sie den Namen der Datenbank in der Konstruktionszeichenfolge.