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.
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 dasTask<ActionResult>
zurückgegebene Objekt automatisch zu erstellen. - Der Rückgabetyp wurde von
ActionResult
zuTask<ActionResult>
. DerTask<T>
Typ stellt die fortlaufende Arbeit mit einem Ergebnis des TypsT
dar. - 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 Create
Methoden 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.
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.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)" ); }
Geben Sie in der Paketverwaltungskonsole den folgenden Befehl ein:
update-database
Führen Sie die Anwendung im Debugmodus aus, klicken Sie auf die Registerkarte "Abteilungen " und dann auf " Neu erstellen".
Geben Sie Daten für eine neue Abteilung ein, und klicken Sie dann auf "Erstellen".
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.
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.
Klicken Sie im Projektmappen-Explorer von Visual Studio mit der rechten Maustaste auf das Projekt, und wählen Sie im Kontextmenü Veröffentlichen aus.
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.
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.