Freigeben über


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

Von Tom Dykstra

Die Contoso University-Beispielwebanwendung veranschaulicht, wie ASP.NET MVC 4-Anwendungen mithilfe von Entity Framework 5 Code First und Visual Studio 2012 erstellt werden. 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 fertige Kapitel herunter, und versuchen Sie, Ihr Problem zu reproduzieren. In der Regel finden Sie die Lösung für das Problem, indem Sie Ihren Code mit dem fertigen Code vergleichen. Einige häufige Fehler und deren Lösung finden Sie unter "Fehler und Problemumgehungen".

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

  • Ausführen unformatierter SQL-Abfragen.
  • Ausführen von No-Tracking-Abfragen.
  • 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 rohe SQL zum Ausführen von Massenaktualisierungen zu verwenden, erstellen Sie eine neue Seite, auf der die Anzahl der Credits aller Kurse in der Datenbank aktualisiert wird:

Screenshot der Startseite

Und um eine No-Tracking-Abfrage zu verwenden, fügen Sie der Seite "Abteilung bearbeiten" neue Validierungslogik hinzu:

Screenshot der Seite

Ausführen von rohen SQL-Abfragen

Die Entity Framework Code First-API enthält Methoden, mit denen Sie SQL-Befehle direkt an die Datenbank übergeben können. Sie haben die folgenden 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 AsNoTracking Methode finden Sie im folgenden Abschnitt.)
  • 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 " 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, wenn 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. Anschließend können Sie eine beliebige Art von Filterung oder Sortierung im Controller angeben, z. B. eine Where Klausel, die von einer Verknüpfung 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 könnten Sie die GetByID Methode verwendet haben, 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 in HomeController.cs ausgeführte Code 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 einen anderen Wert als Entitätsobjekte zurückgibt, was 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 Aktualisierungsabfrage

Angenommen, Contoso University-Administratoren möchten Massenänderungen in der Datenbank ausführen können, z. B. ändern die Anzahl der Credits für jeden Kurs. 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, mit der der Benutzer einen Faktor angeben kann, um den die Anzahl der Credits für alle Kurse geändert werden soll, und Sie nehmen die Änderung vor, indem Sie eine SQL-Anweisung UPDATE ausführen. Die Webseite wird wie die folgende Abbildung aussehen:

Screenshot der Startseite

Im vorherigen Lernprogramm haben Sie das generische Repository zum Lesen und Aktualisieren Course von Entitäten im Course Controller verwendet. Für diesen Massenaktualisierungsvorgang müssen Sie eine neue Repositorymethode erstellen, die sich nicht im generischen Repository befindet. Dazu erstellen Sie eine dedizierte CourseRepository Klasse, die von der GenericRepository Klasse abgeleitet wird.

Erstellen Sie im DAL-Ordner CourseRepository.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 GenericRepository<Course> zuCourseRepository:

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 UpdateCourseCredits Methode hinzu:

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 HttpGet HttpPostfür . Wenn die HttpGet UpdateCourseCredits Methode ausgeführt wird, ist die multiplier Variable NULL, und die Ansicht zeigt ein leeres Textfeld und eine Schaltfläche zum Absenden an, wie in der vorherigen Abbildung dargestellt.

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 im ViewBag Objekt gespeichert wird. Wenn die Ansicht die Anzahl der betroffenen Zeilen im ViewBag Objekt empfängt, wird diese Zahl anstelle des Textfelds und der Schaltfläche "Absenden" angezeigt, wie in der folgenden Abbildung dargestellt:

Screenshot der betroffenen Seite

Erstellen Sie eine Ansicht im Ordner "Ansichten\Kurs " für die Seite "Kursguthaben aktualisieren":

Screenshot des Dialogfelds

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 der Ersten Seite

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

Screenshot der Seite

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

Screenshot der Seite

Weitere Informationen zu unformatierten SQL-Abfragen finden Sie im Teamblog des Entity Framework-Teams.

Abfragen ohne Nachverfolgung

Wenn ein Datenbankkontext Datenbankzeilen abruft und Entitätsobjekte erstellt, die sie darstellen, wird standardmäßig nachverfolgt, ob die Entitäten im Arbeitsspeicher mit den Daten 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.

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

  • Die Abfrage ruft ein so großes Datenvolumen ab, durch das das Deaktivieren der Nachverfolgung möglicherweise spürbar die Leistung verbessert.
  • Sie möchten eine Entität anfügen, um sie zu aktualisieren, aber Sie haben zuvor die gleiche 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, besteht darin, die AsNoTracking Option mit der früheren Abfrage zu verwenden.

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

Fügen Sie in DepartmentController.cs eine neue Methode hinzu, die Sie von den Edit Methoden Create aufrufen können, um sicherzustellen, dass keine beiden 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 im try Block der HttpPost Edit Methode hinzu, um diese neue Methode aufzurufen, wenn keine Überprüfungsfehler auftreten. 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 Kursleiter zu ändern, der bereits der Administrator einer anderen Abteilung ist. Die erwartete Fehlermeldung wird angezeigt:

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 der 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 bearbeitete Abteilung ist, wird kein Fehler gemeldet. Aufgrund dieses Lesevorgangs wird jedoch die englische Abteilungsentität, die aus der Datenbank gelesen wurde, nun vom Datenbankkontext nachverfolgt.
  • Die Edit Methode versucht, die Modified Kennzeichnung für die vom MVC-Modellordner erstellte englische Abteilungsentität festzulegen, aber das schlägt 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, entitäten im Arbeitsspeicher nachzuverfolgen, die von der Überprüfungsabfrage abgerufen werden. Dies hat keinen Nachteil, da Sie diese Entität nicht aktualisieren oder 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 in den folgenden Beispielen dargestellt:

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, wenn der Vorgang erfolgreich ist, und die Website wird wie erwartet an die Seite "Abteilungsindex" zurückgegeben und zeigt den überarbeiteten Budgetwert an.

Untersuchen von Abfragen, die an die Datenbank gesendet wurden

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 Abfragemethode ToString aufrufen. Um dies auszuprobieren, sehen Sie sich eine einfache Abfrage an und sehen sich dann an, was damit passiert, wenn Sie Optionen wie das Laden, Filtern und Sortieren hinzufügen.

Ersetzen Sie in Controller/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(); Anweisungen return orderBy(query).ToList(); 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, überprüfen Sie die query Variable. Die Abfrage, die an SQL Server gesendet wird, wird angezeigt. Es ist 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 der Registerkarte

Abfragen können zu lang sein, um 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 des Variablenwerts mit einem Dropdownmenü, das angezeigt wird, wenn er ausgewählt ist. Die Option

Jetzt 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 das laden 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 Sammlung, die alle Abteilungen enthält, wird an die Ansicht für die Dropdownliste übergeben. Die an den SelectList Konstruktor übergebenen Parameter geben den Namen des Wertfelds, 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 eifriges Laden für die Department Navigationseigenschaft an. Der Filterausdruck gibt immer dann zurück true , wenn in der Dropdownliste nichts ausgewählt ist (d. r SelectedDepartment . null).

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

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

Wenn die Haltepunkte weiterhin im GenericRepository Kurs festgelegt sind, führen Sie die Seite "Kursindex" aus. Fahren Sie mit den ersten beiden Mal fort, wenn der Code auf einen Haltepunkt trifft, sodass die Seite im Browser angezeigt wird. Wählen Sie eine Abteilung aus der Dropdownliste aus, und klicken Sie auf "Filtern":

Screenshot der Seite

Diesmal wird der erste Haltepunkt für die Abteilungsabfrage für die Dropdownliste verwendet. Überspringen Sie dies, und zeigen Sie die query Variable beim nächsten Erreichen des Haltepunkts an, 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ädt Department und dass sie eine WHERE Klausel enthält.

Arbeiten mit Proxyklassen

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

Meistens müssen Sie sich diese Verwendung von Proxys nicht bewusst sein, aber es gibt Ausnahmen:

  • In einigen Szenarien möchten Sie möglicherweise verhindern, dass Entity Framework Proxyinstanzen erstellt. Die Serialisierung von Nicht-Proxyinstanzen kann z. B. effizienter sein als das Serialisieren von Proxyinstanzen.
  • Wenn Sie eine Entitätsklasse mithilfe des new Operators instanziieren, erhalten Sie keine Proxyinstanz. Dies bedeutet, dass Sie keine Funktionen wie das faule Laden und die automatische Änderungsnachverfolgung erhalten. Dies ist in der Regel in Ordnung; Sie benötigen in der Regel keine faule Lademöglichkeit, da Sie eine neue Entität erstellen, die sich nicht in der Datenbank befindet, und Sie benötigen in der Regel keine Änderungsnachverfolgung, wenn Sie die Entität explizit als Addedmarkiert haben. Wenn Sie jedoch faules Laden benötigen und Die Änderungsnachverfolgung erforderlich ist, können Sie neue Entitätsinstanzen mit Proxys mithilfe Create der Methode der DbSet Klasse 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 einer Proxytypinstanz abzurufen.

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

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 mit der AutoDetectChangesEnabled-Eigenschaft vorübergehend 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 Sie die Datenbank aktualisieren. Wenn Sie eine große Anzahl von Entitäten aktualisiert haben und die Daten bereits überprüft haben, ist diese Arbeit unnötig, und Sie können den Vorgang zum Speichern der Änderungen weniger Zeit 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

Dies schließt diese Reihe von Lernprogrammen zur Verwendung von Entity Framework in einer ASP.NET MVC-Anwendung ab. Links zu anderen Entity Framework-Ressourcen finden Sie in der ASP.NET Datenzugriffs-Inhaltszuordnung.

Weitere Informationen zum Bereitstellen Ihrer Webanwendung nach der Erstellung 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 schrieb die originale Version dieses Lernprogramms und ist senior Programming Writer im Microsoft-Webplattform und Tools Content Team.
  • Rick Anderson (Twitter @RickAndMSFT) hat dieses Lernprogramm gemeinsam verfasst und die meisten Arbeiten für EF 5 und MVC 4 aktualisiert. Rick ist senior Programming Writer für Microsoft, der sich auf Azure und MVC konzentriert.
  • Rowan Miller und andere Mitglieder des Entity Framework-Teams unterstützten Codeüberprüfungen und halfen beim Debuggen vieler Probleme mit Migrationen, die während der Aktualisierung des Lernprogramms für EF 5 entstanden sind.

VB

Als das Lernprogramm ursprünglich erstellt wurde, haben wir sowohl C#- als auch VB-Versionen des abgeschlossenen Downloadprojekts bereitgestellt. Mit diesem Update stellen wir für jedes Kapitel ein herunterladbares C#-Projekt bereit, um den Einstieg an eine beliebige Stelle in der Reihe zu erleichtern, aber aufgrund von Zeitbeschränkungen und anderen Prioritäten haben wir dies für VB nicht getan. Wenn Sie ein VB-Projekt mit diesen Lernprogrammen erstellen und diese mit anderen teilen möchten, teilen Sie uns bitte mit.

Fehler und Problemumgehungen

Erstellen/Schattenkopie nicht möglich

Fehlermeldung:

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

Lösung:

Warten Sie einige Sekunden, und aktualisieren Sie die Seite.

Update-Datenbank nicht erkannt

Fehlermeldung:

Der Begriff "Update-Database" wird nicht als Name eines Cmdlets, einer Funktion, einer Skriptdatei oder eines operierbaren 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 eine oder mehrere Entitäten. Weitere Details finden Sie unter der Eigenschaft "EntityValidationErrors". (Aus dem Update-Database Befehl im PMC.)

Lösung:

Eine Ursache dieses Problems ist Überprüfungsfehler, 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, die jeweils dieselbe Portnummer verwenden. 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)

Lösung:

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