Delen via


Zelfstudie: Aan de slag met EF Core een ASP.NET MVC-web-app

Door Tom Dykstra en Rick Anderson

In deze handleiding leert u ASP.NET Core MVC en Entity Framework Core met controllers en views. Razor Pagina's is een alternatief programmeermodel. Voor nieuwe ontwikkeling raden we Razor Pagina's boven MVC met controllers en weergaven aan. Zie de Razor paginaversie van deze zelfstudie. Elke zelfstudie behandelt enig materiaal dat de andere niet behandelt.

Sommige dingen die deze MVC-zelfstudie bevat, heeft de Razor-zelfstudie Pagina's niet.

  • Overname implementeren in het gegevensmodel
  • Onbewerkte SQL-query's uitvoeren
  • Dynamische LINQ gebruiken om code te vereenvoudigen

Sommige dingen die de Razor Pagina's zelfstudie heeft en deze niet:

  • Selecteermethode gebruiken om gerelateerde gegevens te laden
  • Best practices voor EF.

De voorbeeldweb-app van Contoso University laat zien hoe u een ASP.NET Core MVC-web-app maakt met behulp van Entity Framework (EF) Core en Visual Studio.

De voorbeeld-app is een website voor een fictieve Contoso University. Het omvat functionaliteit zoals studententoekenningen, cursuscreatie en docentopdrachten. Dit is de eerste in een reeks zelfstudies waarin wordt uitgelegd hoe u de voorbeeld-app contoso University bouwt.

Prerequisites

Deze handleiding is niet bijgewerkt voor ASP.NET Core in .NET 6 of later. De instructies van de zelfstudie werken niet correct als u een project maakt dat is gericht op ASP.NET Core in .NET 6 of hoger. ASP.NET Core in .NET 6 of latere websjablonen gebruiken bijvoorbeeld het minimale hostingmodel, waarbij Startup.cs en Program.cs worden samengevoegd in één Program.cs-bestand.

Een ander verschil dat is geïntroduceerd in .NET 6, is de NRT-functie (nullable reference types). Met de projectsjablonen wordt deze functie standaard ingeschakeld. Er kunnen problemen optreden waarbij EF een eigenschap beschouwt als vereist in .NET 6, die nullable is in .NET 5. De pagina Student maken mislukt bijvoorbeeld stilletjes, tenzij de Enrollments eigenschap nullable wordt gemaakt of de asp-validation-summary helper-tag wordt gewijzigd van ModelOnly in All.

Het is raadzaam om de .NET 5 SDK voor deze zelfstudie te installeren en te gebruiken. Totdat deze zelfstudie is bijgewerkt, raadpleeg Razor voor het gebruik van Entity Framework met ASP.NET Core in .NET 6 of hoger.

Database engines

De Visual Studio-instructies maken gebruik van SQL Server LocalDB, een versie van SQL Server Express die alleen in Windows wordt uitgevoerd.

Problemen oplossen en storingen opsporen

Als u een probleem ondervindt dat u niet kunt oplossen, kunt u de oplossing over het algemeen vinden door uw code te vergelijken met het voltooide project. Zie de sectie Probleemoplossing van de laatste zelfstudie in de reeks voor een lijst met veelvoorkomende fouten en hoe u deze kunt oplossen. Als u daar niet vindt wat u nodig hebt, kunt u een vraag plaatsen op StackOverflow.com voor ASP.NET Core of EF Core.

Tip

Dit is een reeks van 10 zelfstudies, die elk voortbouwt op wat er in eerdere zelfstudies wordt gedaan. U kunt een kopie van het project opslaan na elke voltooide tutorial. Als u vervolgens problemen ondervindt, kunt u opnieuw beginnen met de vorige zelfstudie in plaats van terug te gaan naar het begin van de hele reeks.

Contoso University webapp

De app die in deze zelfstudies is gebouwd, is een eenvoudige website van de universiteit.

Gebruikers kunnen informatie over studenten, cursussen en docenten bekijken en bijwerken. Hier volgen enkele schermen in de app:

Studentenindexpagina

Pagina Studenten bewerken

Een web-app maken

  1. Start Visual Studio en selecteer Een nieuw project maken.
  2. Selecteer in het dialoogvenster Een nieuw project makenASP.NET Core Web Application>Next.
  3. Voer in het dialoogvenster Configureer uw nieuwe projectContosoUniversity in voor projectnaam. Het is belangrijk om precies deze naam te gebruiken, inclusief hoofdlettergevoeligheid, zodat elke namespace overeenkomt wanneer code wordt gekopieerd.
  4. Select Create.
  5. Selecteer in het dialoogvenster Een nieuwe ASP.NET Core-webtoepassing maken:
    1. .NET Core en ASP.NET Core 5.0 in de vervolgkeuzelijsten.
    2. ASP.NET Core Web App (Model-View-Controller).
    3. MakenNieuw ASP.NET Core Project dialoogvenster

De sitestijl instellen

Enkele basiswijzigingen stellen het sitemenu, de indeling en de startpagina in.

Open Views/Shared/_Layout.cshtml en breng de volgende wijzigingen aan:

  • Wijzig elk voorkomen van ContosoUniversity naar Contoso University. Er zijn drie gebeurtenissen.
  • Voeg menu-items toe voor Info, Studenten, Cursussen, Instructeurs en Afdelingen en verwijder de Privacy menu-vermelding.

De voorgaande wijzigingen zijn gemarkeerd in de volgende code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Contoso University</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Vervang Views/Home/Index.cshtml de inhoud van het bestand door de volgende markup:

@{
    ViewData["Title"] = "Home Page";
}

<div class="jumbotron">
    <h1>Contoso University</h1>
</div>
<div class="row">
    <div class="col-md-4">
        <h2>Welcome to Contoso University</h2>
        <p>
            Contoso University is a sample application that
            demonstrates how to use Entity Framework Core in an
            ASP.NET Core MVC web application.
        </p>
    </div>
    <div class="col-md-4">
        <h2>Build it from scratch</h2>
        <p>You can build the application by following the steps in a series of tutorials.</p>
        <p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">See the tutorial &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Download it</h2>
        <p>You can download the completed project from GitHub.</p>
        <p><a class="btn btn-default" href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-mvc/intro/samples/cu-final">See project source code &raquo;</a></p>
    </div>
</div>

Druk op Ctrl+F5 om het project uit te voeren of kies Foutopsporing > starten zonder foutopsporing in het menu. De startpagina wordt weergegeven met tabbladen voor de pagina's die in deze zelfstudie zijn gemaakt.

Startpagina van Contoso University

EF Core NuGet-pakketten

In deze zelfstudie wordt GEBRUIKgemaakt van SQL Server en het providerpakket is Microsoft.EntityFrameworkCore.SqlServer.

Het EF SQL Server-pakket en de bijbehorende afhankelijkheden Microsoft.EntityFrameworkCore en Microsoft.EntityFrameworkCore.Relationalbieden runtime-ondersteuning voor EF.

Voeg het NuGet-pakket Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore toe. Voer in de Package Manager Console (PMC) de volgende opdrachten in om de NuGet-pakketten toe te voegen:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer

Het Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet-pakket biedt ASP.NET Core-middleware voor EF Core foutpagina's. Deze middleware helpt bij het detecteren en diagnosticeren van fouten met EF Core migraties.

Zie Databaseproviders voor informatie over andere EF Core die beschikbaar zijn voor.

Het gegevensmodel maken

De volgende entiteitsklassen worden gemaakt voor deze app:

Cursus-Enrollment-Student gegevensmodeldiagram

De voorgaande entiteiten hebben de volgende relaties:

  • Een een-op-veel-relatie tussen Student en Enrollment entiteiten. Een student kan worden ingeschreven bij een willekeurig aantal cursussen.
  • Een een-op-veel-relatie tussen Course en Enrollment entiteiten. Een cursus kan een willekeurig aantal leerlingen/studenten hebben ingeschreven.

In de volgende secties wordt een klasse gemaakt voor elk van deze entiteiten.

De entiteit Student

Diagram van studententiteit

Maak in de map Modellen de Student klasse met de volgende code:

using System;
using System.Collections.Generic;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

De ID eigenschap is de primaire sleutelkolom (PK) van de databasetabel die overeenkomt met deze klasse. Standaard interpreteert EF een eigenschap met de naam ID of classnameID als de primaire sleutel. De PK kan bijvoorbeeld de naam StudentID hebben in plaats van ID.

De Enrollments eigenschap is een navigatie-eigenschap. Navigatie-eigenschappen bevatten andere entiteiten die zijn gerelateerd aan deze entiteit. De Enrollments eigenschap van een Student entiteit:

  • Bevat alle Enrollment entiteiten die zijn gerelateerd aan die Student entiteit.
  • Als een specifieke Student rij in de database twee gerelateerde Enrollment rijen heeft:
    • De navigatie-eigenschap van die Student entiteit bevat die twee Enrollments entiteiten.

Enrollmentrijen bevat de PK-waarde van een student in de kolom StudentIDbuitenlandse sleutel (FK).

Als een navigatie-eigenschap meerdere entiteiten kan bevatten:

  • Het type moet een lijst zijn, zoals ICollection<T>, List<T>of HashSet<T>.
  • Entiteiten kunnen worden toegevoegd, verwijderd en bijgewerkt.

Veel-op-veel- en een-op-veel-navigatierelaties kunnen meerdere entiteiten bevatten. Wanneer ICollection<T> wordt gebruikt, maakt EF standaard een HashSet<T> verzameling.

De entiteit Inschrijving

Diagram van inschrijvingsentiteit

Maak in de map Modellen de Enrollment klasse met de volgende code:

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }
}

De EnrollmentID eigenschap is de PK. Deze entiteit gebruikt het classnameID patroon in plaats van ID zelf. De Student entiteit heeft het ID patroon gebruikt. Sommige ontwikkelaars gebruiken liever één patroon in het gegevensmodel. In deze instructie illustreert de variatie dat beide patronen kunnen worden gebruikt. Een latere zelfstudie laat zien hoe het gebruik zonder ID klassenaam het eenvoudiger maakt om overname in het gegevensmodel te implementeren.

De Grade eigenschap is een enum. De ? waarde na de Grade typedeclaratie geeft aan dat de Grade eigenschap nullable is. Een cijfer dat null is anders dan een nulcijfer. null betekent dat een cijfer nog niet bekend is of nog niet is toegewezen.

De StudentID eigenschap is een vreemde sleutel (FK) en de bijbehorende navigatie-eigenschap is Student. Een Enrollment entiteit is gekoppeld aan één Student entiteit, zodat de eigenschap slechts één Student entiteit kan bevatten. Dit verschilt van de Student.Enrollments navigatie-eigenschap, die meerdere Enrollment entiteiten kan bevatten.

De CourseID eigenschap is een FK en de bijbehorende navigatie-eigenschap is Course. Een Enrollment entiteit is gekoppeld aan één Course entiteit.

Entity Framework interpreteert een eigenschap als een FK-eigenschap als deze is genaamd <navigatie-eigenschapsnaam><primaire sleuteleigenschapsnaam>. Bijvoorbeeld StudentID voor de navigatie-eigenschap omdat de PK van de Student entiteit Student is. FK-eigenschappen kunnen ook <primaire-sleuteleigenschap> worden genoemd. Bijvoorbeeld, CourseID omdat de PK van de Course-entiteit CourseID is.

De entiteit Cursus

Diagram van cursusentiteit

Maak in de map Modellen de Course klasse met de volgende code:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

De Enrollments eigenschap is een navigatie-eigenschap. Een Course entiteit kan worden gerelateerd aan een willekeurig aantal Enrollment entiteiten.

Het kenmerk DatabaseGenerated wordt uitgelegd in een latere tutorial. Met dit kenmerk kunt u de PK voor de cursus invoeren in plaats van dat de database deze genereert.

De databasecontext maken

De belangrijkste klasse die EF-functionaliteit coördineert voor een bepaald gegevensmodel, is de DbContext databasecontextklasse. Deze klasse wordt gemaakt door te erven van de Microsoft.EntityFrameworkCore.DbContext klasse. De DbContext afgeleide klasse geeft aan welke entiteiten zijn opgenomen in het gegevensmodel. Sommige EF-gedrag kan worden aangepast. In dit project heeft de klasse de naam SchoolContext.

Maak in de projectmap een map met de naam Data.

Maak in de map Gegevens een SchoolContext klasse met de volgende code:

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }

        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }
    }
}

Met de voorgaande code maakt u een DbSet eigenschap voor elke entiteitsset. In EF-terminologie:

  • Een entiteitsset komt meestal overeen met een databasetabel.
  • Een entiteit komt overeen met een rij in de tabel.

De DbSet<Enrollment> en DbSet<Course> verklaringen kunnen worden weggelaten en het zou hetzelfde werken. EF zou ze impliciet opnemen omdat:

  • De Student entiteit verwijst naar de Enrollment entiteit.
  • De Enrollment entiteit verwijst naar de Course entiteit.

Wanneer de database wordt gemaakt, maakt EF tabellen die dezelfde namen hebben als de DbSet eigenschapsnamen. Eigenschapsnamen voor verzamelingen zijn doorgaans meervoud. Bijvoorbeeld, Students in plaats van Student. Ontwikkelaars zijn het niet eens of tabelnamen wel of niet meervoud moeten zijn. Voor deze zelfstudies wordt het standaardgedrag overschreven door enkelvoudige tabelnamen in DbContext op te geven. Voeg hiervoor de volgende gemarkeerde code toe na de laatste DbSet-eigenschap.

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }

        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
        }
    }
}

Registreer de SchoolContext

ASP.NET Core bevat afhankelijkheidsinjectie. Services, zoals de EF-databasecontext, worden geregistreerd met afhankelijkheidsinjectie tijdens het opstarten van de app. Onderdelen waarvoor deze services, zoals MVC-controllers, zijn vereist, worden deze services geleverd via constructorparameters. De code van de controllerconstructor die een contextinstantie ophaalt, wordt later in deze handleiding weergegeven.

Om SchoolContext als een service te registreren, opent u Startup.cs en voeg de gemarkeerde regels toe aan de ConfigureServices methode.

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace ContosoUniversity
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<SchoolContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddControllersWithViews();
        }

De naam van de verbindingsreeks wordt doorgegeven aan de context door een methode aan te roepen voor een DbContextOptionsBuilder-object. Voor lokale ontwikkeling leest het ASP.NET Core-configuratiesysteem de verbindingsreeks uit het appsettings.json bestand.

Open het appsettings.json bestand en voeg een verbindingsreeks toe, zoals wordt weergegeven in de volgende markeringen:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Het uitzonderingsfilter voor de database toevoegen

Toevoegen AddDatabaseDeveloperPageExceptionFilter aan ConfigureServices zoals wordt weergegeven in de volgende code:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<SchoolContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddDatabaseDeveloperPageExceptionFilter();

    services.AddControllersWithViews();
}

Het AddDatabaseDeveloperPageExceptionFilter biedt nuttige foutinformatie in de ontwikkelomgeving.

SQL Server Express LocalDB

De verbindingsreeks geeft SQL Server LocalDB op. LocalDB is een lichtgewicht versie van de SQL Server Express Database Engine en is bedoeld voor app-ontwikkeling, niet voor productiegebruik. LocalDB start op aanvraag en wordt uitgevoerd in de gebruikersmodus, dus er is geen complexe configuratie. LocalDB maakt standaard .mdf DB-bestanden in de C:/Users/<user>-map.

DB initialiseren met testgegevens

EF maakt een lege database. In deze sectie wordt een methode toegevoegd die wordt aangeroepen nadat de database is gemaakt om deze te vullen met testgegevens.

De EnsureCreated methode wordt gebruikt om automatisch de database te maken. In een latere zelfstudie ziet u hoe u modelwijzigingen kunt afhandelen met behulp van Code First Migrations om het databaseschema te wijzigen in plaats van de database te verwijderen en opnieuw te maken.

Maak in de map Gegevens een nieuwe klasse met de naam DbInitializer met de volgende code:

using ContosoUniversity.Models;
using System;
using System.Linq;

namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            context.Database.EnsureCreated();

            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }

            var students = new Student[]
            {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
            new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
            new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
            };
            foreach (Student s in students)
            {
                context.Students.Add(s);
            }
            context.SaveChanges();

            var courses = new Course[]
            {
            new Course{CourseID=1050,Title="Chemistry",Credits=3},
            new Course{CourseID=4022,Title="Microeconomics",Credits=3},
            new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
            new Course{CourseID=1045,Title="Calculus",Credits=4},
            new Course{CourseID=3141,Title="Trigonometry",Credits=4},
            new Course{CourseID=2021,Title="Composition",Credits=3},
            new Course{CourseID=2042,Title="Literature",Credits=4}
            };
            foreach (Course c in courses)
            {
                context.Courses.Add(c);
            }
            context.SaveChanges();

            var enrollments = new Enrollment[]
            {
            new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
            new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
            new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
            new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
            new Enrollment{StudentID=3,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
            new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
            new Enrollment{StudentID=6,CourseID=1045},
            new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
            };
            foreach (Enrollment e in enrollments)
            {
                context.Enrollments.Add(e);
            }
            context.SaveChanges();
        }
    }
}

Met de voorgaande code wordt gecontroleerd of de database bestaat:

  • Als de database niet wordt gevonden;
    • Het systeem wordt gemaakt en geladen met testgegevens. Er worden testgegevens in arrays geladen in plaats van List<T> verzamelingen om de prestaties te optimaliseren.
  • Als de database wordt gevonden, wordt er geen actie ondernomen.

Werk Program.cs bij met de volgende code:

using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

namespace ContosoUniversity
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();

            CreateDbIfNotExists(host);

            host.Run();
        }

        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    DbInitializer.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

Program.cs doet het volgende bij het opstarten van de app:

  • Haal een databasecontextinstantie op uit de container voor afhankelijkheidsinjectie.
  • Roep de DbInitializer.Initialize methode aan.
  • Verwijder de context wanneer de Initialize methode is voltooid, zoals wordt weergegeven in de volgende code:
public static void Main(string[] args)
{
     var host = CreateWebHostBuilder(args).Build();

    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService<SchoolContext>();
            DbInitializer.Initialize(context);
        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred while seeding the database.");
        }
    }

    host.Run();
}

De eerste keer dat de app wordt uitgevoerd, wordt de database gemaakt en geladen met testgegevens. Wanneer het gegevensmodel wordt gewijzigd:

  • Verwijder de database.
  • Werk de seed-methode bij en begin opnieuw met een nieuwe database.

In latere handleidingen wordt de database gewijzigd bij wijzigingen in het gegevensmodel, zonder deze te verwijderen en opnieuw te maken. Er gaan geen gegevens verloren wanneer het gegevensmodel wordt gewijzigd.

Controller en weergaven maken

Gebruik de scaffolding-engine in Visual Studio om een MVC-controller en weergaven toe te voegen die EF gebruiken om gegevens op te vragen en op te slaan.

Het automatisch maken van CRUD-actiemethoden en -weergaven wordt scaffolding genoemd.

  • Klik in Solution Explorer met de rechtermuisknop op de Controllers map en selecteer Nieuw item met scaffolding toevoegen>.
  • In het dialoogvenster Scaffold toevoegen :
    • Selecteer de MVC-controller met weergaven met behulp van Entity Framework.
    • Click Add. Het dialoogvenster MVC-controller met weergaven toevoegen met behulp van het dialoogvenster Entity Framework wordt weergegeven: Student scaffold
    • Selecteer Student in modelklasse.
    • Selecteer SchoolContext in de gegevenscontextklasse.
    • Accepteer de standaard StudentsController als de naam.
    • Click Add.

De Visual Studio-scaffolding-engine maakt een StudentsController.cs bestand en een set weergaven (*.cshtml bestanden) die met de controller werken.

U ziet dat de controller een SchoolContext constructorparameter heeft.

namespace ContosoUniversity.Controllers
{
    public class StudentsController : Controller
    {
        private readonly SchoolContext _context;

        public StudentsController(SchoolContext context)
        {
            _context = context;
        }

ASP.NET Core-afhankelijkheidsinjectie zorgt ervoor dat een exemplaar van SchoolContext de controller wordt doorgegeven. U hebt dat geconfigureerd in de Startup klasse.

De controller bevat een Index actiemethode waarmee alle leerlingen/studenten in de database worden weergegeven. Met de methode wordt een lijst met leerlingen/studenten gehaald uit de entiteit Students door de Students-eigenschap van de databasecontext te lezen.

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}

De asynchrone programmeerelementen in deze code worden verderop in de zelfstudie uitgelegd.

In Views/Students/Index.cshtml de weergave wordt deze lijst weergegeven in een tabel:

@model IEnumerable<ContosoUniversity.Models.Student>

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
                <th>
                    @Html.DisplayNameFor(model => model.LastName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.FirstMidName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.EnrollmentDate)
                </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Druk op Ctrl+F5 om het project uit te voeren of kies Foutopsporing > starten zonder foutopsporing in het menu.

Klik op het tabblad Leerlingen/studenten om de testgegevens weer te geven die door de DbInitializer.Initialize methode zijn ingevoegd. Afhankelijk van hoe smal uw browservenster is, ziet u de Students tabkoppeling boven aan de pagina of klikt u op het navigatiepictogram in de rechterbovenhoek om de koppeling te zien.

Startpagina van Contoso University smal

Studentenindexpagina

De database weergeven

Wanneer de app wordt gestart, roept de DbInitializer.Initialize methode EnsureCreated aan. EF zag dat er geen database was:

  • Er is dus een database gemaakt.
  • De Initialize methodecode heeft de database gevuld met gegevens.

Gebruik SQL Server Object Explorer (SSOX) om de database in Visual Studio weer te geven:

  • Selecteer SQL Server Object Explorer in het menu Beeld in Visual Studio.
  • Selecteer (localdb)\MSSQLLocalDB-databases >in SSOX.
  • Selecteer ContosoUniversity1, de vermelding voor de databasenaam die zich in de verbindingsreeks in het appsettings.json bestand bevindt.
  • Vouw het knooppunt Tabellen uit om de tabellen in de database weer te geven.

Tabellen in SSOX

Klik met de rechtermuisknop op de tabel Student en klik op Gegevens weergeven om de gegevens in de tabel weer te geven.

Studententabel in SSOX

De *.mdf en *.ldf databasebestanden bevinden zich in de map C:\Users\<username> .

Omdat EnsureCreated deze wordt aangeroepen in de initialisatiemethode die wordt uitgevoerd bij het starten van de app, kunt u het volgende doen:

  • Breng een wijziging aan in de Student klas.
  • Verwijder de database.
  • Stop de app en start deze vervolgens opnieuw. De database wordt automatisch opnieuw gemaakt zodat deze overeenkomt met de wijziging.

Als er bijvoorbeeld een EmailAddress eigenschap wordt toegevoegd aan de Student klasse, wordt er een nieuwe EmailAddress kolom in de opnieuw gemaakte tabel gemaakt. In de weergave wordt de nieuwe EmailAddress eigenschap niet weergegeven.

Conventions

De hoeveelheid code die is geschreven om de EF een volledige database te laten maken, is minimaal vanwege het gebruik van de conventies die EF gebruikt:

  • De namen van DbSet eigenschappen worden gebruikt als tabelnamen. Voor entiteiten waarnaar niet wordt verwezen door een DbSet eigenschap, worden namen van entiteitsklassen gebruikt als tabelnamen.
  • Namen van entiteitseigenschappen worden gebruikt voor kolomnamen.
  • Entiteitseigenschappen die een naam ID hebben of classnameID die worden herkend als PK-eigenschappen.
  • Een eigenschap wordt geïnterpreteerd als een FK-eigenschap als deze de naam <navigatie-eigenschap><PK-eigenschap> heeft. Bijvoorbeeld StudentID voor de navigatie-eigenschap omdat de PK van de Student entiteit Student is. FK-eigenschappen kunnen ook <primaire-sleuteleigenschap> worden genoemd. Bijvoorbeeld, EnrollmentID aangezien de PK van de Enrollment entiteit EnrollmentID is.

Conventioneel gedrag kan worden genegeerd. Tabelnamen kunnen bijvoorbeeld expliciet worden opgegeven, zoals eerder in deze zelfstudie wordt weergegeven. Kolomnamen en elke eigenschap kunnen worden ingesteld als PK of FK.

Asynchronous code

Asynchrone programmering is de standaardmodus voor ASP.NET Core en EF Core.

Een webserver heeft een beperkt aantal threads beschikbaar en in situaties met hoge belasting kunnen alle beschikbare threads in gebruik zijn. Als dat gebeurt, kan de server geen nieuwe aanvragen verwerken totdat de threads zijn vrijgemaakt. Met synchrone code kunnen veel threads worden gekoppeld terwijl ze eigenlijk geen werk doen, omdat ze wachten tot I/O is voltooid. Met asynchrone code, wanneer een proces wacht tot I/O is voltooid, wordt de thread vrijgemaakt zodat de server deze kan gebruiken voor het verwerken van andere aanvragen. Als gevolg hiervan stelt asynchrone code serverresources in staat efficiënter te worden gebruikt, waardoor de server meer verkeer kan verwerken zonder vertraging.

Asynchrone code introduceert een kleine hoeveelheid overhead tijdens runtime, maar voor situaties met weinig verkeer is de prestatietreffer te verwaarlozen, terwijl voor situaties met veel verkeer de potentiële prestatieverbetering aanzienlijk is.

In de volgende code zorgen async, Task<T>, await en ToListAsync ervoor dat de code asynchroon wordt uitgevoerd.

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
  • Het async trefwoord vertelt de compiler om callbacks te genereren voor delen van de methode en automatisch het Task<IActionResult> object te maken dat moet worden geretourneerd.
  • Het retourtype Task<IActionResult> vertegenwoordigt doorlopend werk met een resultaat van het type IActionResult.
  • Het await trefwoord zorgt ervoor dat de compiler de methode in twee delen splitst. Het eerste deel eindigt met de bewerking die asynchroon is gestart. Het tweede deel wordt in een callback-methode geplaatst die wordt aangeroepen wanneer de bewerking is voltooid.
  • ToListAsync is de asynchrone versie van de ToList extensiemethode.

Enkele dingen waar u rekening mee moet houden bij het schrijven van asynchrone code die gebruikmaakt van EF:

  • Alleen instructies die ertoe leiden dat query's of opdrachten naar de database worden verzonden, worden asynchroon uitgevoerd. Dat omvat bijvoorbeeld ToListAsync, en SingleOrDefaultAsyncSaveChangesAsync. Het bevat bijvoorbeeld geen uitspraken die alleen een IQueryable wijzigen, zoals var students = context.Students.Where(s => s.LastName == "Davolio").
  • Een EF-context is niet threadveilig: probeer niet meerdere bewerkingen parallel uit te voeren. Wanneer u een asynchrone EF-methode aanroept, gebruikt u altijd het await trefwoord.
  • Als u wilt profiteren van de prestatievoordelen van asynchrone code, moet u ervoor zorgen dat bibliotheekpakketten die worden gebruikt ook asynchroon worden gebruikt als ze EF-methoden aanroepen die ertoe leiden dat query's naar de database worden verzonden.

Zie Async-overzicht voor meer informatie over asynchrone programmering in .NET.

Opgehaalde entiteiten beperken

Zie Prestatieoverwegingen voor informatie over het beperken van het aantal entiteiten dat door een query wordt geretourneerd.

SQL-logboekregistratie van Entity Framework Core

Configuratie van logboeken wordt doorgaans geleverd door het gedeelte Logging van appsettings.{Environment}.json bestanden. Als u SQL-instructies wilt vastleggen, voegt u "Microsoft.EntityFrameworkCore.Database.Command": "Information" toe aan het appsettings.Development.json-bestand:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDB-2;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
     ,"Microsoft.EntityFrameworkCore.Database.Command": "Information"
    }
  },
  "AllowedHosts": "*"
}

Met de voorgaande JSON worden SQL-instructies weergegeven op de opdrachtregel en in het uitvoervenster van Visual Studio.

Zie Logboekregistratie in .NET en ASP.NET Core en dit GitHub-probleem voor meer informatie.

Ga naar de volgende zelfstudie voor meer informatie over het uitvoeren van eenvoudige CRUD-bewerkingen (maken, lezen, bijwerken, verwijderen).

In deze handleiding leert u ASP.NET Core MVC en Entity Framework Core met controllers en views. Razor Pagina's is een alternatief programmeermodel. Voor nieuwe ontwikkeling raden we Razor Pagina's boven MVC met controllers en weergaven aan. Zie de Razor paginaversie van deze zelfstudie. Elke zelfstudie behandelt enig materiaal dat de andere niet behandelt.

Sommige dingen die deze MVC-zelfstudie bevat, heeft de Razor-zelfstudie Pagina's niet.

  • Overname implementeren in het gegevensmodel
  • Onbewerkte SQL-query's uitvoeren
  • Dynamische LINQ gebruiken om code te vereenvoudigen

Sommige dingen die de Razor Pagina's zelfstudie heeft en deze niet:

  • Selecteermethode gebruiken om gerelateerde gegevens te laden
  • Best practices voor EF.

De voorbeeldwebtoepassing contoso University laat zien hoe u ASP.NET Core 2.2 MVC-webtoepassingen maakt met behulp van Entity Framework (EF) Core 2.2 en Visual Studio 2019.

Deze zelfstudie is niet bijgewerkt voor ASP.NET Core 3.1. Het is bijgewerkt voor ASP.NET Core in .NET 5.

De voorbeeldtoepassing is een website voor een fictieve Contoso University. Het omvat functionaliteit zoals studententoekenningen, cursuscreatie en docentopdrachten. Dit is de eerste in een reeks zelfstudies waarin wordt uitgelegd hoe u de volledig nieuwe voorbeeldtoepassing van Contoso University bouwt.

Prerequisites

Troubleshooting

Als u een probleem ondervindt dat u niet kunt oplossen, kunt u de oplossing over het algemeen vinden door uw code te vergelijken met het voltooide project. Zie de sectie Probleemoplossing van de laatste zelfstudie in de reeks voor een lijst met veelvoorkomende fouten en hoe u deze kunt oplossen. Als u daar niet vindt wat u nodig hebt, kunt u een vraag plaatsen op StackOverflow.com voor ASP.NET Core of EF Core.

Tip

Dit is een reeks van 10 zelfstudies, die elk voortbouwt op wat er in eerdere zelfstudies wordt gedaan. U kunt een kopie van het project opslaan na elke voltooide tutorial. Als u vervolgens problemen ondervindt, kunt u opnieuw beginnen met de vorige zelfstudie in plaats van terug te gaan naar het begin van de hele reeks.

Contoso University webapp

De toepassing die u in deze zelfstudies bouwt, is een eenvoudige website van de universiteit.

Gebruikers kunnen informatie over studenten, cursussen en docenten bekijken en bijwerken. Hier volgen enkele schermen die u gaat maken.

Studentenindexpagina

Pagina Studenten bewerken

Een web-app maken

  • Open Visual Studio.

  • Selecteer in het menu >.

  • In het linkerdeelvenster, selecteer Geïnstalleerde > Visual C# > Web.

  • Selecteer het ASP.NET Core Web Application-projectsjabloon.

  • Voer ContosoUniversity in als de naam en klik op OK.

    Nieuw project dialoogvenster

  • Wacht tot het dialoogvenster Nieuwe ASP.NET Core-webtoepassing wordt weergegeven.

  • Selecteer .NET Core, ASP.NET Core 2.2 en de sjabloon webtoepassing (model-View-Controller).

  • Zorg ervoor dat verificatie is ingesteld op Geen verificatie.

  • Select OK

    Nieuw ASP.NET Core Project Dialoogvenster

De sitestijl instellen

Met enkele eenvoudige wijzigingen wordt het sitemenu, de indeling en de startpagina ingesteld.

Open Views/Shared/_Layout.cshtml en breng de volgende wijzigingen aan:

  • Wijzig elk exemplaar van "ContosoUniversity" in "Contoso University". Er zijn drie gebeurtenissen.

  • Voeg menu-items toe voor Info, Studenten, Cursussen, Instructeurs en Afdelingen en verwijder de Privacy menu-vermelding.

De wijzigingen zijn gemarkeerd.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Contoso University</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
              crossorigin="anonymous"
              integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
    </environment>
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <partial name="_CookieConsentPartial" />
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2019 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>

    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
        </script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
        </script>
    </environment>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>

Vervang Views/Home/Index.cshtmlde inhoud van het bestand door de volgende code om de tekst over ASP.NET en MVC te vervangen door tekst over deze toepassing:

@{
    ViewData["Title"] = "Home Page";
}

<div class="jumbotron">
    <h1>Contoso University</h1>
</div>
<div class="row">
    <div class="col-md-4">
        <h2>Welcome to Contoso University</h2>
        <p>
            Contoso University is a sample application that
            demonstrates how to use Entity Framework Core in an
            ASP.NET Core MVC web application.
        </p>
    </div>
    <div class="col-md-4">
        <h2>Build it from scratch</h2>
        <p>You can build the application by following the steps in a series of tutorials.</p>
        <p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">See the tutorial &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Download it</h2>
        <p>You can download the completed project from GitHub.</p>
        <p><a class="btn btn-default" href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-mvc/intro/samples/cu-final">See project source code &raquo;</a></p>
    </div>
</div>

Druk op Ctrl+F5 om het project uit te voeren of kies Foutopsporing > starten zonder foutopsporing in het menu. U ziet de startpagina met tabbladen voor de pagina's die u in deze zelfstudies gaat maken.

Startpagina van Contoso University

Over EF Core NuGet-pakketten

Als u ondersteuning wilt toevoegen EF Core aan een project, installeert u de databaseprovider waarop u zich wilt richten. In deze zelfstudie wordt GEBRUIKgemaakt van SQL Server en het providerpakket is Microsoft.EntityFrameworkCore.SqlServer. Dit pakket is opgenomen in het Microsoft.AspNetCore.App metapackage, dus u hoeft niet naar het pakket te verwijzen.

Het EF SQL Server-pakket en de bijbehorende afhankelijkheden (Microsoft.EntityFrameworkCore en Microsoft.EntityFrameworkCore.Relational) bieden runtime-ondersteuning voor EF. U voegt later een hulpprogrammapakket toe in de zelfstudie Migraties .

Zie Databaseproviders voor informatie over andere databaseproviders die beschikbaar zijn voor Entity Framework Core.

Het gegevensmodel maken

Vervolgens maakt u entiteitsklassen voor de Contoso University-toepassing. U begint met de volgende drie entiteiten.

Cursus-Enrollment-Student gegevensmodeldiagram

Er is een een-op-veel-relatie tussen Student en Enrollment entiteiten en er is een een-op-veel-relatie tussen Course en Enrollment entiteiten. Met andere woorden, een student kan worden ingeschreven in een willekeurig aantal cursussen en een cursus kan een willekeurig aantal studenten hebben ingeschreven.

In de volgende secties maakt u een klasse voor elk van deze entiteiten.

De entiteit Student

Diagram van studententiteit

Maak in de map Modellen een klassebestand met de naam Student.cs en vervang de sjablooncode door de volgende code.

using System;
using System.Collections.Generic;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

De ID eigenschap wordt de primaire sleutelkolom van de databasetabel die overeenkomt met deze klasse. Het Entity Framework interpreteert standaard een eigenschap met de naam ID of classnameID als primaire sleutel.

De Enrollments eigenschap is een navigatie-eigenschap. Navigatie-eigenschappen bevatten andere entiteiten die zijn gerelateerd aan deze entiteit. In dit geval bevat de Enrollments eigenschap van een bestand Student entity alle Enrollment entiteiten die zijn gerelateerd aan die Student entiteit. Met andere woorden, als een Student rij in de database twee gerelateerde Enrollment rijen heeft (rijen die de primaire sleutelwaarde van die student bevatten in hun StudentID vreemde-sleutelkolom), bevat de navigatie-eigenschap van die Student entiteit deze twee Enrollments entiteiten.

Als een navigatie-eigenschap meerdere entiteiten kan bevatten (zoals in veel-op-veel- of een-op-veel-relaties), moet het bijbehorende type een lijst zijn waarin vermeldingen kunnen worden toegevoegd, verwijderd en bijgewerkt, zoals ICollection<T>. U kunt ICollection<T> opgeven of een type zoals List<T> of HashSet<T>. Als u opgeeft ICollection<T>, maakt EF standaard een HashSet<T> verzameling.

De entiteit Inschrijving

Diagram van inschrijvingsentiteit

Maak en vervang de bestaande code in de map Enrollment.cs door de volgende code:

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }
}

De EnrollmentID eigenschap is de primaire sleutel. Deze entiteit gebruikt het classnameID patroon in plaats van ID zelf zoals u in de Student entiteit hebt gezien. Normaal gesproken kiest u één patroon en gebruikt u dit in uw gegevensmodel. Hier ziet u in de variatie dat u een van beide patronen kunt gebruiken. In een latere zelfstudie ziet u hoe het gebruik van id zonder klassenaam het eenvoudiger maakt om overname in het gegevensmodel te implementeren.

De Grade eigenschap is een enum. Het vraagteken na de Grade typedeclaratie geeft aan dat de Grade eigenschap nullable is. Een cijfer dat null is, verschilt van een nulcijfer. Null betekent dat een cijfer nog niet bekend is of nog niet is toegewezen.

De StudentID eigenschap is een vreemde sleutel en de bijbehorende navigatie-eigenschap is Student. Een Enrollment entiteit is gekoppeld aan één Student entiteit, zodat de eigenschap slechts één Student entiteit kan bevatten (in tegenstelling tot de Student.Enrollments navigatie-eigenschap die u eerder hebt gezien, die meerdere Enrollment entiteiten kan bevatten).

De CourseID eigenschap is een vreemde sleutel en de bijbehorende navigatie-eigenschap is Course. Een Enrollment entiteit is gekoppeld aan één Course entiteit.

Entity Framework interpreteert een eigenschap als een vreemde-sleuteleigenschap als deze de naam <navigation property name><primary key property name> heeft (bijvoorbeeld StudentID voor de navigatie-eigenschap omdat de primaire sleutel van de Student entiteit Student is ID). Een eigenschap van een refererende sleutel kan ook eenvoudig <primary key property name> worden genoemd (bijvoorbeeld CourseID omdat de primaire sleutel van de Course-entiteit CourseID is).

De entiteit Cursus

Diagram van cursusentiteit

Maak en vervang de bestaande code in de map Course.cs door de volgende code:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

De Enrollments eigenschap is een navigatie-eigenschap. Een Course entiteit kan worden gerelateerd aan een willekeurig aantal Enrollment entiteiten.

In een DatabaseGenerated in deze reeks vindt u meer informatie over het kenmerk. In principe kunt u met dit kenmerk de primaire sleutel voor de cursus invoeren in plaats van de database deze te laten genereren.

De databasecontext maken

De belangrijkste klasse die de functionaliteit van Entity Framework coördineert voor een bepaald gegevensmodel, is de contextklasse van de database. U maakt deze klasse door deze te afleiden van de Microsoft.EntityFrameworkCore.DbContext klasse. In uw code geeft u op welke entiteiten zijn opgenomen in het gegevensmodel. U kunt ook bepaald Gedrag van Entity Framework aanpassen. In dit project heeft de klasse de naam SchoolContext.

Maak in de projectmap een map met de naam Gegevens.

Maak in de map Gegevens een nieuw klassebestand met de naam SchoolContext.csen vervang de sjablooncode door de volgende code:

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }

        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }
    }
}

Met deze code maakt u een DbSet eigenschap voor elke entiteitsset. In entity Framework-terminologie komt een entiteitsset meestal overeen met een databasetabel en een entiteit komt overeen met een rij in de tabel.

U zou de DbSet<Enrollment> en DbSet<Course> instructies kunnen weglaten en het zou nog steeds op dezelfde manier werken. Het Entity Framework bevat deze impliciet omdat de Student entiteit verwijst naar de Enrollment entiteit en de Enrollment entiteit verwijst naar de Course entiteit.

Wanneer de database wordt gemaakt, maakt EF tabellen die dezelfde namen hebben als de DbSet eigenschapsnamen. Eigenschapsnamen voor verzamelingen zijn doorgaans in het meervoud (Studenten in plaats van Student), maar ontwikkelaars zijn het er niet over eens of tabelnamen moeten worden gepluraliseerd of niet. Voor deze zelfstudies overschrijft u het standaardgedrag door enkelvoudige tabelnamen op te geven in DbContext. Voeg hiervoor de volgende gemarkeerde code toe na de laatste DbSet-eigenschap.

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }

        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
        }
    }
}

Bouw het project als controle op compilerfouten.

SchoolContext registreren

ASP.NET Core implementeert standaard afhankelijkheidsinjectie . Services (zoals de EF-databasecontext) worden geregistreerd met afhankelijkheidsinjectie tijdens het opstarten van de toepassing. Onderdelen waarvoor deze services (zoals MVC-controllers) zijn vereist, worden geleverd via constructorparameters. Later in deze zelfstudie zie je de controller-constructorcode die een context-exemplaar ophaalt.

Om SchoolContext als een service te registreren, opent u Startup.cs en voeg de gemarkeerde regels toe aan de ConfigureServices methode.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddDbContext<SchoolContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddMvc();
}

De naam van de verbindingsreeks wordt doorgegeven aan de context door een methode aan te roepen voor een DbContextOptionsBuilder-object. Voor lokale ontwikkeling leest het ASP.NET Core-configuratiesysteem de verbindingsreeks uit het appsettings.json bestand.

Voeg using-instructies toe voor de ContosoUniversity.Data- en Microsoft.EntityFrameworkCore-naamruimten en bouw vervolgens het project.

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Http;

Open het appsettings.json bestand en voeg een verbindingsreeks toe, zoals wordt weergegeven in het volgende voorbeeld.

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  }
}

SQL Server Express LocalDB

De verbindingsreeks geeft een LOCALDB-database van SQL Server op. LocalDB is een lichtgewicht versie van de SQL Server Express Database Engine en is bedoeld voor het ontwikkelen van toepassingen, niet voor productiegebruik. LocalDB start op aanvraag en wordt uitgevoerd in de gebruikersmodus, dus er is geen complexe configuratie. LocalDB maakt standaard .mdf databasebestanden in de C:/Users/<user> map.

DB initialiseren met testgegevens

Het Entity Framework maakt een lege database voor u. In deze sectie schrijft u een methode die wordt aangeroepen nadat de database is gemaakt om deze te vullen met testgegevens.

Hier gebruikt u de EnsureCreated methode om automatisch de database te maken. In een latere zelfstudie ziet u hoe u modelwijzigingen kunt afhandelen met behulp van Code First Migrations om het databaseschema te wijzigen in plaats van de database te verwijderen en opnieuw te maken.

Maak in de map Gegevens een nieuw klassebestand met de naam DbInitializer.cs en vervang de sjablooncode door de volgende code, waardoor een database indien nodig wordt gemaakt en testgegevens in de nieuwe database wordt geladen.

using ContosoUniversity.Models;
using System;
using System.Linq;

namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            context.Database.EnsureCreated();

            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }

            var students = new Student[]
            {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
            new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
            new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
            };
            foreach (Student s in students)
            {
                context.Students.Add(s);
            }
            context.SaveChanges();

            var courses = new Course[]
            {
            new Course{CourseID=1050,Title="Chemistry",Credits=3},
            new Course{CourseID=4022,Title="Microeconomics",Credits=3},
            new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
            new Course{CourseID=1045,Title="Calculus",Credits=4},
            new Course{CourseID=3141,Title="Trigonometry",Credits=4},
            new Course{CourseID=2021,Title="Composition",Credits=3},
            new Course{CourseID=2042,Title="Literature",Credits=4}
            };
            foreach (Course c in courses)
            {
                context.Courses.Add(c);
            }
            context.SaveChanges();

            var enrollments = new Enrollment[]
            {
            new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
            new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
            new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
            new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
            new Enrollment{StudentID=3,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
            new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
            new Enrollment{StudentID=6,CourseID=1045},
            new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
            };
            foreach (Enrollment e in enrollments)
            {
                context.Enrollments.Add(e);
            }
            context.SaveChanges();
        }
    }
}

De code controleert of er leerlingen/studenten zijn in de database. Als dat niet het geval is, wordt ervan uitgegaan dat de database nieuw is en moet worden gezaaid met testgegevens. Er worden testgegevens in arrays geladen in plaats van List<T> verzamelingen om de prestaties te optimaliseren.

Wijzig Program.cs, zodat de Main-methode het volgende doet bij het opstarten van de toepassing:

  • Haal een databasecontextinstantie op uit de container voor afhankelijkheidsinjectie.
  • Roep de seed-methode aan en geef de context als parameter.
  • Verwijder de context na het uitvoeren van de seed-methode.
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

namespace ContosoUniversity
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();

            CreateDbIfNotExists(host);

            host.Run();
        }

        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    DbInitializer.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

De eerste keer dat u de toepassing uitvoert, wordt de database gemaakt en geseed met testgegevens. Wanneer u het gegevensmodel wijzigt:

  • Verwijder de database.
  • Werk de seed-methode bij en begin opnieuw met een nieuwe database op dezelfde manier.

In latere zelfstudies ziet u hoe u de database kunt wijzigen wanneer het gegevensmodel wordt gewijzigd, zonder deze te verwijderen en opnieuw te maken.

Controller en weergaven maken

In deze sectie wordt de scaffolding-engine in Visual Studio gebruikt om een MVC-controller en weergaven toe te voegen die EF gebruiken om gegevens op te vragen en op te slaan.

Het automatisch maken van CRUD-actiemethoden en -weergaven wordt scaffolding genoemd. Scaffolding verschilt van het genereren van code omdat de geveerde code een uitgangspunt is dat u kunt aanpassen aan uw eigen vereisten, terwijl u doorgaans geen gegenereerde code wijzigt. Wanneer u gegenereerde code moet aanpassen, gebruikt u gedeeltelijke klassen of genereert u de code opnieuw wanneer dingen veranderen.

  • Klik met de rechtermuisknop op de map Controllers in Solution Explorer en selecteer Voeg gescaffold nieuw item toe>.
  • In het dialoogvenster Scaffold toevoegen :
    • Selecteer de MVC-controller met weergaven met behulp van Entity Framework.
    • Click Add. Het dialoogvenster MVC-controller met weergaven toevoegen met behulp van het dialoogvenster Entity Framework wordt weergegeven: Student scaffold
    • Selecteer student in modelklasse.
    • Selecteer SchoolContext in de gegevenscontextklasse.
    • Accepteer de standaard StudentsController als de naam.
    • Click Add.

De Visual Studio-scaffolding-engine maakt een StudentsController.cs bestand en een set weergaven (.cshtml bestanden) die met de controller werken.

U ziet dat de controller een SchoolContext constructorparameter heeft.

namespace ContosoUniversity.Controllers
{
    public class StudentsController : Controller
    {
        private readonly SchoolContext _context;

        public StudentsController(SchoolContext context)
        {
            _context = context;
        }

ASP.NET Core-afhankelijkheidsinjectie zorgt ervoor dat een exemplaar van SchoolContext de controller wordt doorgegeven. Dat is geconfigureerd in het Startup.cs bestand.

De controller bevat een Index actiemethode waarmee alle leerlingen/studenten in de database worden weergegeven. Met de methode wordt een lijst met leerlingen/studenten gehaald uit de entiteit Students door de Students-eigenschap van de databasecontext te lezen.

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}

Verderop in de zelfstudie leert u meer over de asynchrone programmeerelementen in deze code.

In Views/Students/Index.cshtml de weergave wordt deze lijst weergegeven in een tabel:

@model IEnumerable<ContosoUniversity.Models.Student>

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
                <th>
                    @Html.DisplayNameFor(model => model.LastName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.FirstMidName)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.EnrollmentDate)
                </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.LastName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.FirstMidName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EnrollmentDate)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Druk op Ctrl+F5 om het project uit te voeren of kies Foutopsporing > starten zonder foutopsporing in het menu.

Klik op het tabblad Leerlingen/studenten om de testgegevens weer te geven die door de DbInitializer.Initialize methode zijn ingevoegd. Afhankelijk van hoe smal uw browservenster is, ziet u de Students tabkoppeling boven aan de pagina of klikt u op het navigatiepictogram in de rechterbovenhoek om de koppeling te zien.

Startpagina van Contoso University smal

Studentenindexpagina

De database weergeven

Wanneer u de toepassing hebt gestart, roept de DbInitializer.Initialize-methode EnsureCreated aan. EF zag dat er geen database was en dus er een is gemaakt, waarna de rest van de Initialize methodecode de database vulde met gegevens. U kunt SQL Server Object Explorer (SSOX) gebruiken om de database in Visual Studio weer te geven.

Sluit de browser.

Als het SSOX-venster nog niet is geopend, selecteert u het in het menu Beeld in Visual Studio.

Klik in SSOX op (localdb)\MSSQLLocalDB-databases >en klik vervolgens op de vermelding voor de databasenaam die zich in de verbindingsreeks in het appsettings.json bestand bevindt.

Vouw het knooppunt Tabellen uit om de tabellen in de database weer te geven.

Tabellen in SSOX

Klik met de rechtermuisknop op de tabel Student en klik op Gegevens weergeven om de kolommen te zien die zijn gemaakt en de rijen die in de tabel zijn ingevoegd.

Studententabel in SSOX

De .mdf- en LDF-databasebestanden bevinden zich in de map C:\Users\<username> .

Omdat u de initializermethode aanroept EnsureCreated die wordt uitgevoerd bij het starten van de app, kunt u nu een wijziging aanbrengen in de Student klasse, de database verwijderen, de toepassing opnieuw uitvoeren en de database automatisch opnieuw worden gemaakt om aan uw wijziging te voldoen. Als u bijvoorbeeld een EmailAddress eigenschap aan de Student klasse toevoegt, ziet u een nieuwe EmailAddress kolom in de tabel die opnieuw is gemaakt.

Conventions

De hoeveelheid code die u moest schrijven om het Entity Framework in staat te stellen een volledige database voor u te maken, is minimaal vanwege het gebruik van conventies of veronderstellingen die het Entity Framework maakt.

  • De namen van DbSet eigenschappen worden gebruikt als tabelnamen. Voor entiteiten waarnaar niet wordt verwezen door een DbSet eigenschap, worden namen van entiteitsklassen gebruikt als tabelnamen.
  • Namen van entiteitseigenschappen worden gebruikt voor kolomnamen.
  • Entiteitseigenschappen met de naam ID of classnameID worden herkend als primaire-sleuteleigenschappen.
  • Een eigenschap wordt geïnterpreteerd als een refererende sleuteleigenschap als deze de naam<>< van de primaire sleuteleigenschap> van de navigatie-eigenschap heeft (bijvoorbeeld StudentID voor de Student navigatie-eigenschap omdat de primaire sleutel van de Student entiteit isID). Eigenschappen van refererende sleutels kunnen ook gewoon <de naam> van de primaire sleuteleigenschap worden genoemd (bijvoorbeeld omdat EnrollmentID de primaire sleutel van de Enrollment entiteit isEnrollmentID).

Conventioneel gedrag kan worden genegeerd. U kunt bijvoorbeeld expliciet tabelnamen opgeven, zoals u eerder in deze zelfstudie hebt gezien. En u kunt kolomnamen instellen en elke eigenschap als primaire sleutel of vreemde sleutel instellen, zoals u zult zien in een latere zelfstudie in deze reeks.

Asynchronous code

Asynchrone programmering is de standaardmodus voor ASP.NET Core en EF Core.

Een webserver heeft een beperkt aantal threads beschikbaar en in situaties met hoge belasting kunnen alle beschikbare threads in gebruik zijn. Als dat gebeurt, kan de server geen nieuwe aanvragen verwerken totdat de threads zijn vrijgemaakt. Met synchrone code kunnen veel threads worden gekoppeld terwijl ze eigenlijk geen werk doen, omdat ze wachten tot I/O is voltooid. Met asynchrone code, wanneer een proces wacht tot I/O is voltooid, wordt de thread vrijgemaakt zodat de server deze kan gebruiken voor het verwerken van andere aanvragen. Als gevolg hiervan stelt asynchrone code serverresources in staat efficiënter te worden gebruikt, waardoor de server meer verkeer kan verwerken zonder vertraging.

Asynchrone code introduceert een kleine hoeveelheid overhead tijdens runtime, maar voor situaties met weinig verkeer is de prestatietreffer te verwaarlozen, terwijl voor situaties met veel verkeer de potentiële prestatieverbetering aanzienlijk is.

In de volgende code zorgen het async trefwoord, de Task<T> retourwaarde, het await trefwoord en de ToListAsync methode ervoor dat de code asynchroon wordt uitgevoerd.

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
  • Het async trefwoord vertelt de compiler om callbacks te genereren voor delen van de methode en automatisch het Task<IActionResult> object te maken dat moet worden geretourneerd.
  • Het retourtype Task<IActionResult> vertegenwoordigt doorlopend werk met een resultaat van het type IActionResult.
  • Het await trefwoord zorgt ervoor dat de compiler de methode in twee delen splitst. Het eerste deel eindigt met de bewerking die asynchroon is gestart. Het tweede deel wordt in een callback-methode geplaatst die wordt aangeroepen wanneer de bewerking is voltooid.
  • ToListAsync is de asynchrone versie van de ToList extensiemethode.

Enkele dingen waar u rekening mee moet houden wanneer u asynchrone code schrijft die gebruikmaakt van het Entity Framework:

  • Alleen instructies die ertoe leiden dat query's of opdrachten naar de database worden verzonden, worden asynchroon uitgevoerd. Dat omvat bijvoorbeeld ToListAsync, en SingleOrDefaultAsyncSaveChangesAsync. Het bevat bijvoorbeeld geen uitspraken die alleen een IQueryable wijzigen, zoals var students = context.Students.Where(s => s.LastName == "Davolio").
  • Een EF-context is niet threadveilig: probeer niet meerdere bewerkingen parallel uit te voeren. Wanneer u een asynchrone EF-methode aanroept, gebruikt u altijd het await trefwoord.
  • Als u wilt profiteren van de prestatievoordelen van asynchrone code, moet u ervoor zorgen dat bibliotheekpakketten die u gebruikt (zoals voor paging), ook asynchroon gebruiken als ze Entity Framework-methoden aanroepen die ertoe leiden dat query's naar de database worden verzonden.

Zie Async-overzicht voor meer informatie over asynchrone programmering in .NET.

Next steps

Ga naar de volgende zelfstudie voor meer informatie over het uitvoeren van eenvoudige CRUD-bewerkingen (maken, lezen, bijwerken, verwijderen).