Freigeben über


Lernprogramm: Verwenden asynchroner und gespeicherter Prozeduren mit EF in einer ASP.NET MVC-App

In früheren Lernprogrammen haben Sie gelernt, wie Sie Daten mithilfe des synchronen Programmiermodells lesen und aktualisieren. In diesem Lernprogramm erfahren Sie, wie Sie das asynchrone Programmiermodell implementieren. Asynchroner Code kann einer Anwendung dabei helfen, eine bessere Leistung zu erzielen, da die Serverressourcen besser genutzt werden.

In diesem Lernprogramm erfahren Sie auch, wie Sie gespeicherte Prozeduren für Einfüge-, Aktualisierungs- und Löschvorgänge für eine Entität verwenden.

Schließlich stellen Sie die Anwendung erneut in Azure bereit, zusammen mit allen Datenbankänderungen, die Sie seit der ersten Bereitstellung implementiert haben.

In den folgenden Abbildungen werden die Seiten dargestellt, mit denen Sie arbeiten werden.

Seite

Abteilung erstellen

In diesem Tutorial:

  • Informationen zu asynchronen Code
  • Erstellen eines Abteilungscontrollers
  • Verwenden von gespeicherten Prozeduren
  • In Azure bereitstellen

Voraussetzungen

Gründe für die Verwendung asynchronen Codes

Der Webserver verfügt nur über eine begrenzte Anzahl von Threads. Daher werden bei hoher Auslastung möglicherweise alle verfügbaren Threads gleichzeitig verwendet. Wenn dies der Fall ist, kann der Server keine neuen Anforderungen verarbeiten, bis die Threads wieder freigegeben werden. Wenn synchroner Code verwendet wird, kann es sein, dass zwar viele Threads belegt sind, diese aber keine Vorgänge ausführen, da sie auf den Abschluss der E/A-Vorgänge warten. Wenn asynchroner Code verwendet wird, werden Threads für den Server freigegeben, wenn diese nur auf den Abschluss der E/A-Vorgänge warten, damit andere Anforderungen verarbeitet werden können. Aus diesem Grund können Serverressourcen mit asynchronem Code effizienter verwendet werden, und der Server kann ohne Verzögerungen mehr Datenverkehr verarbeiten.

In früheren Versionen von .NET war das Schreiben und Testen asynchroner Code komplex, fehleranfällig und schwer zu debuggen. In .NET 4.5 ist das Schreiben, Testen und Debuggen von asynchronem Code so viel einfacher, dass Sie asynchronen Code in der Regel schreiben sollten, es sei denn, Sie haben keinen Grund. Asynchroner Code führt einen geringen Mehraufwand ein, aber für niedrige Datenverkehrssituationen ist der Leistungstreffer vernachlässigbar, während bei hohen Datenverkehrssituationen die potenzielle Leistungsverbesserung erheblich ist.

Weitere Informationen zur asynchronen Programmierung finden Sie unter Verwenden der asynchronen .NET 4.5-Unterstützung, um das Blockieren von Aufrufen zu vermeiden.

Abteilungscontroller erstellen

Erstellen Sie einen Abteilungscontroller auf die gleiche Weise wie die früheren Controller, außer diesmal aktivieren Sie das Kontrollkästchen "Asynchrone Controlleraktionen verwenden".

Die folgenden Highlights zeigen, was dem synchronen Code für die Index Methode hinzugefügt wurde, um sie asynchron zu machen:

public async Task<ActionResult> Index()
{
    var departments = db.Departments.Include(d => d.Administrator);
    return View(await departments.ToListAsync());
}

Vier Änderungen wurden angewendet, um die Asynchrone Ausführung der Entity Framework-Datenbankabfrage zu ermöglichen:

  • Die Methode wird mit dem async Schlüsselwort markiert, das dem Compiler angibt, Rückrufe für Teile des Methodentexts zu generieren und das Task<ActionResult> zurückgegebene Objekt automatisch zu erstellen.
  • Der Rückgabetyp wurde von ActionResult zu Task<ActionResult>. Der Task<T> Typ stellt die fortlaufende Arbeit mit einem Ergebnis des Typs Tdar.
  • Das await Schlüsselwort wurde auf den Webdienstaufruf angewendet. Wenn der Compiler dieses Schlüsselwort sieht, teilt er hinter den Kulissen die Methode in zwei Teile auf. Der erste Teil endet mit dem Vorgang, der asynchron gestartet wird. Der zweite Teil wird in eine Rückrufmethode eingefügt, die aufgerufen wird, wenn der Vorgang abgeschlossen ist.
  • Die asynchrone Version der ToList Erweiterungsmethode wurde aufgerufen.

Warum wird die departments.ToList Anweisung geändert, aber nicht die departments = db.Departments Anweisung? Der Grund dafür ist, dass nur Anweisungen, die dazu führen, dass Abfragen oder Befehle asynchron an die Datenbank gesendet werden. Die departments = db.Departments Anweisung richtet eine Abfrage ein, die Abfrage wird jedoch erst ausgeführt, wenn die ToList Methode aufgerufen wird. Daher wird nur die ToList Methode asynchron ausgeführt.

Bei der Methode und den Details Delete HttpGet Edit Methoden handelt es sich bei der Find Methode um die Methode, die bewirkt, dass eine Abfrage an die Datenbank gesendet wird. Dies ist die Methode, die asynchron ausgeführt wird:

public async Task<ActionResult> Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Department department = await db.Departments.FindAsync(id);
    if (department == null)
    {
        return HttpNotFound();
    }
    return View(department);
}

In den CreateMethoden HttpPost Edit, und DeleteConfirmed Methoden ist es der SaveChanges Methodenaufruf, der bewirkt, dass ein Befehl ausgeführt wird, nicht Anweisungen, z db.Departments.Add(department) . B. die nur dazu führen, dass Entitäten im Arbeitsspeicher geändert werden.

public async Task<ActionResult> Create(Department department)
{
    if (ModelState.IsValid)
    {
        db.Departments.Add(department);
    await db.SaveChangesAsync();
        return RedirectToAction("Index");
    }

Öffnen Sie Views\Department\Index.cshtml, und ersetzen Sie den Vorlagencode durch den folgenden Code:

@model IEnumerable<ContosoUniversity.Models.Department>
@{
    ViewBag.Title = "Departments";
}
<h2>Departments</h2>
<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Budget)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.StartDate)
        </th>
    <th>
            Administrator
        </th>
        <th></th>
    </tr>
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Budget)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.StartDate)
        </td>
    <td>
            @Html.DisplayFor(modelItem => item.Administrator.FullName)
            </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |
            @Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })
        </td>
    </tr>
}
</table>

Dieser Code ändert den Titel von Index in Abteilungen, verschiebt den Administratornamen nach rechts und stellt den vollständigen Namen des Administrators bereit.

Ändern Sie in den Ansichten "Erstellen", "Löschen", "Details" und "Bearbeiten" die Beschriftung für das InstructorID Feld auf "Administrator" auf die gleiche Weise wie das Feld "Abteilung" in den Kursansichten in "Abteilung".

Verwenden Sie in den Ansichten "Erstellen und Bearbeiten" den folgenden Code:

<label class="control-label col-md-2" for="InstructorID">Administrator</label>

Verwenden Sie in den Ansichten "Löschen" und "Details" den folgenden Code:

<dt>
    Administrator
</dt>

Führen Sie die Anwendung aus, und klicken Sie auf die Registerkarte "Abteilungen ".

Alles funktioniert genauso wie in den anderen Controllern, aber in diesem Controller werden alle SQL-Abfragen asynchron ausgeführt.

Einige Dinge, die Sie beachten müssen, wenn Sie die asynchrone Programmierung mit Entity Framework verwenden:

  • Der asynchrone Code ist nicht threadsicher. Mit anderen Worten: Versuchen Sie nicht, mehrere Vorgänge parallel mit derselben Kontextinstanz auszuführen.
  • Wenn Sie von den Leistungsvorteilen des asynchronen Codes profitieren möchten, vergewissern Sie sich, dass auch alle Bibliothekspakete, die Sie verwenden (z.B. zum Paging) asynchronen Code verwenden, wenn sie Entity Framework Core-Methoden aufrufen, die Abfragen an die Datenbank senden.

Verwenden von gespeicherten Prozeduren

Einige Entwickler und DBAs bevorzugen die Verwendung gespeicherter Prozeduren für den Datenbankzugriff. In früheren Versionen von Entity Framework können Sie Daten mithilfe einer gespeicherten Prozedur abrufen, indem Sie eine unformatierte SQL-Abfrage ausführen, aber Sie können EF nicht anweisen, gespeicherte Prozeduren für Aktualisierungsvorgänge zu verwenden. In EF 6 ist es einfach, Code First so zu konfigurieren, dass gespeicherte Prozeduren verwendet werden.

  1. Fügen Sie in DAL\SchoolContext.cs der Methode den hervorgehobenen Code hinzu OnModelCreating .

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Entity<Course>()
            .HasMany(c => c.Instructors).WithMany(i => i.Courses)
            .Map(t => t.MapLeftKey("CourseID")
                .MapRightKey("InstructorID")
                .ToTable("CourseInstructor"));
        modelBuilder.Entity<Department>().MapToStoredProcedures();
    }
    

    Dieser Code weist Entity Framework an, gespeicherte Prozeduren für Einfüge-, Aktualisierungs- und Löschvorgänge für die Department Entität zu verwenden.

  2. Geben Sie in der Paketverwaltungskonsole den folgenden Befehl ein:

    add-migration DepartmentSP

    Öffnen Sie Migrationen\<Zeitstempel>_DepartmentSP.cs um den Code in der Methode anzuzeigen, mit der Up gespeicherte Prozeduren "Einfügen", "Aktualisieren" und "Löschen" erstellt werden:

    public override void Up()
    {
        CreateStoredProcedure(
            "dbo.Department_Insert",
            p => new
                {
                    Name = p.String(maxLength: 50),
                    Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),
                    StartDate = p.DateTime(),
                    InstructorID = p.Int(),
                },
            body:
                @"INSERT [dbo].[Department]([Name], [Budget], [StartDate], [InstructorID])
                  VALUES (@Name, @Budget, @StartDate, @InstructorID)
                  
                  DECLARE @DepartmentID int
                  SELECT @DepartmentID = [DepartmentID]
                  FROM [dbo].[Department]
                  WHERE @@ROWCOUNT > 0 AND [DepartmentID] = scope_identity()
                  
                  SELECT t0.[DepartmentID]
                  FROM [dbo].[Department] AS t0
                  WHERE @@ROWCOUNT > 0 AND t0.[DepartmentID] = @DepartmentID"
        );
        
        CreateStoredProcedure(
            "dbo.Department_Update",
            p => new
                {
                    DepartmentID = p.Int(),
                    Name = p.String(maxLength: 50),
                    Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"),
                    StartDate = p.DateTime(),
                    InstructorID = p.Int(),
                },
            body:
                @"UPDATE [dbo].[Department]
                  SET [Name] = @Name, [Budget] = @Budget, [StartDate] = @StartDate, [InstructorID] = @InstructorID
                  WHERE ([DepartmentID] = @DepartmentID)"
        );
        
        CreateStoredProcedure(
            "dbo.Department_Delete",
            p => new
                {
                    DepartmentID = p.Int(),
                },
            body:
                @"DELETE [dbo].[Department]
                  WHERE ([DepartmentID] = @DepartmentID)"
        );    
    }
    
  3. Geben Sie in der Paketverwaltungskonsole den folgenden Befehl ein:

    update-database

  4. Führen Sie die Anwendung im Debugmodus aus, klicken Sie auf die Registerkarte "Abteilungen " und dann auf " Neu erstellen".

  5. Geben Sie Daten für eine neue Abteilung ein, und klicken Sie dann auf "Erstellen".

  6. Sehen Sie sich in Visual Studio die Protokolle im Ausgabefenster an, um zu sehen, dass eine gespeicherte Prozedur verwendet wurde, um die neue Zeile "Abteilung" einzufügen.

    Abteilung einfügen SP

Code First erstellt Standardmäßige gespeicherte Prozedurnamen. Wenn Sie eine vorhandene Datenbank verwenden, müssen Sie möglicherweise die Namen der gespeicherten Prozeduren anpassen, um gespeicherte Prozeduren zu verwenden, die bereits in der Datenbank definiert sind. Informationen dazu finden Sie unter "Entity Framework Code First Insert/Update/Delete Stored Procedures".

Wenn Sie anpassen möchten, was generierte gespeicherte Prozeduren tun, können Sie den Gerüstcode für die Migrationsmethode Up bearbeiten, die die gespeicherte Prozedur erstellt. Auf diese Weise werden Ihre Änderungen immer dann übernommen, wenn diese Migration ausgeführt wird und auf Ihre Produktionsdatenbank angewendet wird, wenn Migrationen nach der Bereitstellung automatisch in der Produktion ausgeführt werden.

Wenn Sie eine vorhandene gespeicherte Prozedur ändern möchten, die in einer vorherigen Migration erstellt wurde, können Sie den Befehl "Add-Migration" verwenden, um eine leere Migration zu generieren, und dann manuell Code schreiben, der die AlterStoredProcedure-Methode aufruft.

Bereitstellung in Azure

In diesem Abschnitt müssen Sie den optionalen Abschnitt "Bereitstellen der App in Azure " im Lernprogramm "Migrationen und Bereitstellung " dieser Reihe abgeschlossen haben. Wenn Sie Migrationsfehler hatten, die Sie behoben haben, indem Sie die Datenbank in Ihrem lokalen Projekt löschen, überspringen Sie diesen Abschnitt.

  1. Klicken Sie im Projektmappen-Explorer von Visual Studio mit der rechten Maustaste auf das Projekt, und wählen Sie im Kontextmenü Veröffentlichen aus.

  2. Klicken Sie auf Veröffentlichen.

    Visual Studio stellt die Anwendung in Azure bereit, und die Anwendung wird in Ihrem Standardbrowser geöffnet, der in Azure ausgeführt wird.

  3. Testen Sie die Anwendung, um zu überprüfen, ob sie funktioniert.

    Wenn Sie zum ersten Mal eine Seite ausführen, die auf die Datenbank zugreift, führt Entity Framework alle Migrationsmethoden Up aus, die erforderlich sind, um die Datenbank mit dem aktuellen Datenmodell auf dem neuesten Stand zu bringen. Sie können jetzt alle Webseiten verwenden, die Sie seit der letzten Bereitstellung hinzugefügt haben, einschließlich der Abteilungsseiten, die Sie in diesem Lernprogramm hinzugefügt haben.

Abrufen des Codes

Herunterladen des abgeschlossenen Projekts

Zusätzliche Ressourcen

Links zu anderen Entity Framework-Ressourcen finden Sie im ASP.NET Datenzugriff – Empfohlene Ressourcen.

Nächste Schritte

In diesem Tutorial haben Sie:

  • Erfahren Sie mehr über asynchronen Code
  • Erstellt einen Abteilungscontroller
  • Verwendete gespeicherte Prozeduren
  • Bereitgestellt in Azure

Wechseln Sie zum nächsten Artikel, um zu erfahren, wie Konflikte behandelt werden, wenn mehrere Benutzer die gleiche Entität gleichzeitig aktualisieren.