Delen via


Razor Pagina's met Entity Framework Core in ASP.NET Core - Zelfstudie 1 van 8

Note

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikel voor de huidige release.

Warning

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 9-versie van dit artikel voor de huidige release.

Important

Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.

Zie de .NET 9-versie van dit artikel voor de huidige release.

Door Tom Dykstra, Jeremy Likness en Jon P Smith

Dit is de eerste in een reeks zelfstudies die laten zien hoe u Entity Framework (EF) Core gebruikt in een app ASP.NET Core Razor Pages . De handleidingen bouwen een website voor het fictieve "Contoso University". De site bevat functionaliteit zoals toelating van studenten, het maken van cursussen en docentopdrachten. In de tutorial wordt de code-first benadering gebruikt. Zie dit GitHub-probleem voor informatie over het volgen van deze zelfstudie met behulp van de eerste benadering van de database.

Download of bekijk de voltooide app.Downloadinstructies.

Prerequisites

Database-engines

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

Troubleshooting

Als u een probleem ondervindt dat u niet kunt oplossen, vergelijkt u de code met het voltooide project. Een goede manier om hulp te krijgen is door een vraag te plaatsen op StackOverflow.com, met behulp van de ASP.NET Core-tag of de EF Core tag.

De voorbeeld-app

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 die in de zelfstudie zijn gemaakt.

Studentenindexpagina

Pagina Studenten bewerken

De gebruikersinterfacestijl van deze site is gebaseerd op de ingebouwde projectsjablonen. De focus van de zelfstudie ligt op het gebruik EF Core met ASP.NET Core, niet op het aanpassen van de gebruikersinterface.

Optioneel: het voorbeeld voor downloaden bouwen

Deze stap is optioneel. Het bouwen van de voltooide app wordt aanbevolen wanneer u problemen ondervindt die u niet kunt oplossen. Als u een probleem ondervindt dat u niet kunt oplossen, vergelijkt u de code met het voltooide project. Downloadinstructies.

Selecteer ContosoUniversity.csproj om het project te openen.

  • Bouw het project.

  • Voer in Package Manager Console (PMC) de volgende opdracht uit:

    Update-Database
    

Voer het project uit om de database te seeden.

Het web-app-project maken

  1. Start Visual Studio 2022 en selecteer Een nieuw project maken.

    Een nieuw project maken vanuit het startvenster

  2. Selecteer in het dialoogvenster Een nieuw project makenASP.NET Core Web App en selecteer vervolgens Volgende.

    Een ASP.NET Core-web-app maken

  3. Voer in het dialoogvenster ContosoUniversity voor Projectnaam in. Het is belangrijk om het project ContosoUniversity een naam te geven, inclusief overeenkomend met het hoofdlettergebruik, zodat de naamruimten overeenkomen wanneer u voorbeeldcode kopieert en plakt.

  4. Kies Volgende.

  5. Selecteer in het dialoogvenster Aanvullende informatie.NET 6.0 (langetermijnondersteuning) en selecteer vervolgens Maken.

    Aanvullende informatie

De sitestijl instellen

Kopieer en plak de volgende code in het Pages/Shared/_Layout.cshtml bestand:

<!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" asp-append-version="true" />
    <link rel="stylesheet" href="~/ContosoUniversity.styles.css" asp-append-version="true" />
</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-page="/Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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-page="/About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Departments/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; 2021 - Contoso University - <a asp-area="" asp-page="/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>

Het indelingsbestand stelt de sitekoptekst, voettekst en menu in. De voorgaande code brengt de volgende wijzigingen aan:

  • Elke voorkomst van 'ContosoUniversity' veranderd naar 'Contoso University'. Er zijn drie gebeurtenissen.
  • De Home en Privacy menu-items worden verwijderd.
  • Vermeldingen worden toegevoegd voor About, Students, Courses, Instructors en Afdelingen.

Vervang Pages/Index.cshtmlde inhoud van het bestand door de volgende code:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="row mb-auto">
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 mb-4 ">
                <p class="card-text">
                    Contoso University is a sample application that
                    demonstrates how to use Entity Framework Core in an
                    ASP.NET Core Razor Pages web app.
                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column position-static">
                <p class="card-text mb-auto">
                    You can build the application by following the steps in a series of tutorials.
                </p>
                <p>
@*                    <a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
*@                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column">
                <p class="card-text mb-auto">
                    You can download the completed project from GitHub.
                </p>
                <p>
@*                    <a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
*@                </p>
            </div>
        </div>
    </div>
</div>

De voorgaande code vervangt de tekst over ASP.NET Core door tekst over deze app.

Voer de app uit om te controleren of de startpagina wordt weergegeven.

Het gegevensmodel

In de volgende secties wordt een gegevensmodel gemaakt:

Cursus-Enrollment-Student gegevensmodeldiagram

Een student kan zich inschrijven voor een willekeurig aantal cursussen en een cursus kan een willekeurig aantal studenten hebben ingeschreven.

De entiteit Student

Diagram van studententiteit

  • Maak een map Modellen in de projectmap.
  • Maak Models/Student.cs met de volgende code:
    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. Interpreteert standaard EF Core een eigenschap met de naam ID of classnameID als de primaire sleutel. De alternatieve automatisch herkende naam voor de primaire sleutel van de Student klasse is StudentIDdus. Zie - Sleutels voor meer informatieEF Core.

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 Student entiteit alle Enrollment entiteiten die zijn gerelateerd aan die student. Als een rij Student in de database bijvoorbeeld twee gerelateerde inschrijvingsrijen heeft, bevat de Enrollments navigatie-eigenschap deze twee inschrijvingsentiteiten.

In de database is een inschrijvingsrij gerelateerd aan een rij Student als de StudentID kolom de id-waarde van de student bevat. Stel dat een rij Student id=1 heeft. Gerelateerde inschrijvingsrijen hebben StudentID = 1. StudentID is een vreemde sleutel in de tabel Inschrijving.

De Enrollments-eigenschap is als ICollection<Enrollment> gedefinieerd omdat er mogelijk meerdere gerelateerde ingeschreven entiteiten zijn. Andere verzamelingstypen kunnen worden gebruikt, zoals List<Enrollment> of HashSet<Enrollment>. Wanneer ICollection<Enrollment> wordt gebruikt, creëert EF Core standaard een HashSet<Enrollment> verzameling.

De entiteit Inschrijving

Diagram van inschrijvingsentiteit

Maak Models/Enrollment.cs met de volgende code:

using System.ComponentModel.DataAnnotations;

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; }
        [DisplayFormat(NullDisplayText = "No grade")]
        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. Voor een productiegegevensmodel kiezen veel ontwikkelaars één patroon en gebruiken ze dit consistent. In deze tutorial maakt men gebruik van beide om te illustreren dat beide werken. Het gebruiken van ID zonder classname maakt het eenvoudiger om bepaalde soorten wijzigingen in gegevensmodellen 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, dus de eigenschap bevat één Student entiteit.

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

EF Core interpreteert een eigenschap als een vreemde sleutel als deze de naam <navigation property name><primary key property name> heeft. Bijvoorbeeld, StudentID is de refererende sleutel voor de Student navigatie-eigenschap, aangezien de primaire sleutel van de Student entiteit ID is. Eigenschappen van refererende sleutels kunnen ook een naam <primary key property name>hebben. Omdat de primaire sleutel van de CourseID entiteit bijvoorbeeld Course isCourseID.

De entiteit Cursus

Diagram van cursusentiteit

Maak Models/Course.cs met de volgende code:

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.

Met DatabaseGenerated het kenmerk kan de app de primaire sleutel opgeven in plaats van de database deze te laten genereren.

Maak de app. De compiler genereert verschillende waarschuwingen over hoe null waarden worden verwerkt. Bekijk dit GitHub-probleem, null-referentietypen en zelfstudie: Uw ontwerpintentie duidelijker uitdrukken met null-en niet-null-referentietypen voor meer informatie.

Verwijder de volgende regel uit het bestand ContosoUniversity.csproj om de waarschuwingen van nullable referentietypen te elimineren:

<Nullable>enable</Nullable>

De scaffolding-engine biedt momenteel geen ondersteuning voor null-referentietypen, dus de modellen die in de scaffold worden gebruikt, kunnen ook niet.

Verwijder de notatie van het ? null-waarde-toelaatbare referentietype uit public string? RequestId { get; set; } in Pages/Error.cshtml.cs zodat het project zonder compilerwaarschuwingen buildt.

Scaffold-pagina's voor leerlingen/studenten

In deze sectie wordt het hulpprogramma ASP.NET Core-scaffolding gebruikt om het volgende te genereren:

  • Een EF CoreDbContext klas. De context is de belangrijkste klasse die de Functionaliteit van Entity Framework coördineert voor een bepaald gegevensmodel. Het is afgeleid van de Microsoft.EntityFrameworkCore.DbContext klasse.
  • Razor pagina's die CRUD-bewerkingen (Create, Read, Update en Delete) voor de Student entiteit verwerken.
  • Maak een map Pagina's/leerlingen/studenten .
  • Klik in Solution Explorer met de rechtermuisknop op de map Pages/Students en selecteer Toevoegen>Nieuw ge-scaffolded item.
  • In het dialoogvenster Nieuw steigeronderdeel toevoegen:
    • Selecteer in het linkertabblad geïnstalleerde > algemene >Razor pagina's
    • Selecteer Razor pagina's met behulp van Entity Framework (CRUD)>Toevoegen.
  • In het dialoogvenster Pagina's toevoegen Razor met behulp van Entity Framework (CRUD):
    • Selecteer Student (ContosoUniversity.Models) in de vervolgkeuzelijst Modelklasse.
    • Selecteer in de rij Gegevenscontextklasse het + (plusteken).
      • Wijzig de naam van de gegevenscontext zodat deze eindigt SchoolContext in plaats ContosoUniversityContextvan . De bijgewerkte contextnaam: ContosoUniversity.Data.SchoolContext
      • Selecteer Toevoegen om de gegevenscontextklasse toe te voegen.
      • Selecteer Toevoegen om het dialoogvenster Pagina's toevoegen Razor te voltooien.

De volgende pakketten worden automatisch geïnstalleerd:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Als de voorgaande stap mislukt, bouwt u het project en probeert u de stap van het steigerelement opnieuw uit te voeren.

Het steigerproces:

  • Hiermee maakt u Razor pagina's in de map Pages/Students:
    • Create.cshtml en Create.cshtml.cs
    • Delete.cshtml en Delete.cshtml.cs
    • Details.cshtml en Details.cshtml.cs
    • Edit.cshtml en Edit.cshtml.cs
    • Index.cshtml en Index.cshtml.cs
  • Maakt Data/SchoolContext.cs.
  • Voegt de context toe aan afhankelijkheidsinjectie in Program.cs.
  • Hiermee voegt u een databaseverbindingsreeks toe aan appsettings.json.

database-verbindingstekenreeks

Het hulpprogramma voor scaffolding genereert een verbindingsreeks in het appsettings.json bestand.

De verbindingsreeks geeft SQL Server LocalDB op:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=SchoolContext-0e9;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

LocalDB is een lichtgewicht versie van de SQL Server Express Database Engine en is bedoeld voor app-ontwikkeling, niet voor productiegebruik. LocalDB maakt standaard .mdf bestanden in de C:/Users/<user> map.

De databasecontextklasse bijwerken

De belangrijkste klasse die de functionaliteit voor een bepaald gegevensmodel coördineert EF Core , is de contextklasse van de database. De context is afgeleid van Microsoft.EntityFrameworkCore.DbContext. De context geeft aan welke entiteiten zijn opgenomen in het gegevensmodel. In dit project heeft de klasse de naam SchoolContext.

Werk Data/SchoolContext.cs bij met de volgende code:

using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;

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

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

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

De voorgaande code verandert van de enkelvoud DbSet<Student> Student in het meervoud DbSet<Student> Students. Om de Razor Pagina's-code overeen te laten komen met de nieuwe DBSet naam, voert u een globale wijziging door van: _context.Student. Aan: _context.Students.

Er zijn 8 voorkomens.

Omdat een entiteitsset meerdere entiteiten bevat, geven veel ontwikkelaars de voorkeur aan de DBSet eigenschapsnamen in meervoud.

De gemarkeerde code:

  • Hiermee maakt u een DbSet<TEntity> eigenschap voor elke entiteitsset. In EF Core terminologie:
    • Een entiteitsset komt meestal overeen met een databasetabel.
    • Een entiteit komt overeen met een rij in de tabel.
  • Roept OnModelCreating aan. OnModelCreating:
    • Wordt aangeroepen wanneer SchoolContext is geïnitialiseerd, maar voordat het model wordt beveiligd en gebruikt om de context te initialiseren.
    • Is vereist omdat de Student entiteit later in de instructies naar de andere entiteiten zal verwijzen.

We hopen dit probleem in een toekomstige release op te lossen.

Program.cs

ASP.NET Core is gebouwd met afhankelijkheidsinjectie. Services zoals de SchoolContext services worden geregistreerd met afhankelijkheidsinjectie tijdens het opstarten van de app. Componenten die deze services vereisen, zoals Razor pagina's, ontvangen deze services via constructorparameters. De constructorcode die een databasecontextinstantie ophaalt, wordt verderop in de zelfstudie weergegeven.

Het hulpprogramma voor scaffolding registreerde automatisch de contextklasse met de container voor afhankelijkheidsinjectie.

De volgende gemarkeerde lijnen zijn toegevoegd door de scaffolder:

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDbContext<SchoolContext>(options =>
  options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext")));

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

Het uitzonderingsfilter voor de database toevoegen

Voeg AddDatabaseDeveloperPageExceptionFilter toe en UseMigrationsEndPoint zoals wordt weergegeven in de volgende code:

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDbContext<SchoolContext>(options =>
  options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext")));

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
else
{
    app.UseDeveloperExceptionPage();
    app.UseMigrationsEndPoint();
}

Voeg het NuGet-pakket Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore toe.

Voer in de Package Manager-console het volgende in om het NuGet-pakket toe te voegen:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore

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

De AddDatabaseDeveloperPageExceptionFilter biedt nuttige foutinformatie in de ontwikkelomgeving voor EF-migratiefouten.

De database maken

Werk Program.cs bij om de database te maken als deze niet bestaat:

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDbContext<SchoolContext>(options =>
  options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext")));

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
else
{
    app.UseDeveloperExceptionPage();
    app.UseMigrationsEndPoint();
}

using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    var context = services.GetRequiredService<SchoolContext>();
    context.Database.EnsureCreated();
    // DbInitializer.Initialize(context);
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

De EnsureCreated methode voert geen actie uit als er een database voor de context bestaat. Als er geen database bestaat, worden de database en het schema gemaakt. EnsureCreated maakt de volgende werkstroom mogelijk voor het verwerken van wijzigingen in gegevensmodellen:

  • Verwijder de database. Alle bestaande gegevens gaan verloren.
  • Wijzig het gegevensmodel. Voeg bijvoorbeeld een EmailAddress veld toe.
  • Voer de app uit.
  • EnsureCreated maakt een database met het nieuwe schema.

Deze werkstroom werkt vroeg in ontwikkeling wanneer het schema zich snel ontwikkelt, zolang gegevens niet hoeven te worden bewaard. De situatie verschilt wanneer gegevens die in de database zijn ingevoerd, moeten worden bewaard. Als dat het geval is, gebruik migraties.

Later in de reeks zelfstudies wordt de database die is aangemaakt door EnsureCreated verwijderd en vervolgens worden migraties gebruikt. Een database die wordt gemaakt door EnsureCreated , kan niet worden bijgewerkt met behulp van migraties.

De app testen

  • Voer de app uit.
  • Selecteer de koppeling Leerlingen/studenten en vervolgens Nieuwe maken.
  • Test de koppelingen Bewerken, Details en Verwijderen.

De database vullen met gegevens

Met de EnsureCreated methode wordt een lege database gemaakt. In deze sectie wordt code toegevoegd waarmee de database wordt gevuld met testgegevens.

Maak Data/DbInitializer.cs met de volgende code:

using ContosoUniversity.Models;

namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            // 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("2019-09-01")},
                new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
                new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
            };

            context.Students.AddRange(students);
            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}
            };

            context.Courses.AddRange(courses);
            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},
            };

            context.Enrollments.AddRange(enrollments);
            context.SaveChanges();
        }
    }
}

De code controleert of er leerlingen/studenten zijn in de database. Als er geen leerlingen/studenten zijn, worden er testgegevens aan de database toegevoegd. Hiermee worden de testgegevens in matrices gemaakt in plaats List<T> van verzamelingen om de prestaties te optimaliseren.

  • Verwijder Program.cs uit de // regel in DbInitializer.Initialize.
using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    var context = services.GetRequiredService<SchoolContext>();
    context.Database.EnsureCreated();
    DbInitializer.Initialize(context);
}
  • Stop de app als deze wordt uitgevoerd en voer de volgende opdracht uit in de Package Manager Console (PMC):

    Drop-Database -Confirm
    
    
  • Reageer met Y om de database te verwijderen.

  • Start de app opnieuw op.
  • Selecteer de pagina Leerlingen/studenten om de gezaaide gegevens weer te geven.

De database weergeven

  • Open SQL Server Object Explorer (SSOX) in het menu Beeld in Visual Studio.
  • Selecteer in SSOX de (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. De databasenaam wordt gegenereerd op basis van de contextnaam die u eerder hebt opgegeven, plus een streepje en een GUID.
  • Vouw het knooppunt Tabellen uit.
  • Klik met de rechtermuisknop op de tabel Student en klik op Gegevens weergeven om de kolommen weer te geven die zijn gemaakt en de rijen die zijn ingevoegd in de tabel.
  • Klik met de rechtermuisknop op de tabel Student en klik op Code weergeven om te zien hoe het Student model wordt toegewezen aan het Student tabelschema.

Asynchrone EF-methoden in ASP.NET Core-web-apps

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 bezet zijn terwijl ze niet werken 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. Hierdoor kan asynchrone code serverresources efficiënter worden gebruikt en kan de server zonder vertragingen meer verkeer verwerken.

Asynchrone code introduceert een kleine hoeveelheid overhead tijdens runtime. Voor lage-verkeersituaties is de impact op de prestaties te verwaarlozen, terwijl voor hoge-verkeersituaties de potentiële prestatieverbetering aanzienlijk is.

In de volgende code wordt het asynchrone trefwoord, Task de retourwaarde, await het trefwoord en ToListAsync de methode asynchroon uitgevoerd.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Het async trefwoord vertelt de compiler aan:
    • Callbacks genereren voor delen van de hoofdtekst van de methode.
    • Maak het taakobject dat wordt geretourneerd.
  • Het Task retourtype vertegenwoordigt doorlopend werk.
  • 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 Core:

  • Alleen instructies die ertoe leiden dat query's of opdrachten naar de database worden verzonden, worden asynchroon uitgevoerd. Dat omvat ToListAsync, SingleOrDefaultAsync, en FirstOrDefaultAsyncSaveChangesAsync. Het bevat geen uitspraken die alleen een IQueryable veranderen, zoals var students = context.Students.Where(s => s.LastName == "Davolio").
  • Een EF Core context is niet thread-veilig: probeer niet meerdere bewerkingen parallel uit te voeren.
  • Als u wilt profiteren van de prestatievoordelen van asynchrone code, controleert u of bibliotheekpakketten (zoals voor paging) asynchroon worden gebruikt als ze methoden aanroepen EF Core waarmee query's naar de database worden verzonden.

Zie Async Overview en Asynchroon programmeren met async en await voor meer informatie over asynchrone programmering in .NET.

Warning

De asynchrone implementatie van Microsoft.Data.SqlClient heeft enkele bekende problemen (#593, #601 en andere). Als u onverwachte prestatieproblemen ondervindt, kunt u in plaats daarvan de uitvoering van de synchronisatieopdracht gebruiken, met name wanneer u te maken hebt met grote tekst- of binaire waarden.

Prestatieoverwegingen

Over het algemeen mag een webpagina geen willekeurig aantal rijen laden. Een query moet paginering of een beperkende benadering gebruiken. De voorgaande query kan bijvoorbeeld worden gebruikt Take om de geretourneerde rijen te beperken:

public async Task OnGetAsync()
{
    Student = await _context.Students.Take(10).ToListAsync();
}

Bij het opsommen van een grote tabel in een weergave kan een gedeeltelijk opgebouwd HTTP 200-antwoord worden geretourneerd als er een database-uitzondering optreedt tijdens de opsomming.

Paging wordt verderop in de zelfstudie behandeld.

Zie Prestatieoverwegingen (EF) voor meer informatie.

Volgende stappen

SQLite gebruiken voor ontwikkeling, SQL Server voor productie

Dit is de eerste in een reeks zelfstudies die laten zien hoe u Entity Framework (EF) Core gebruikt in een app ASP.NET Core Razor Pages . De handleidingen bouwen een website voor het fictieve "Contoso University". De site bevat functionaliteit zoals toelating van studenten, het maken van cursussen en docentopdrachten. In de tutorial wordt de code-first benadering gebruikt. Zie dit GitHub-probleem voor informatie over het volgen van deze zelfstudie met behulp van de eerste benadering van de database.

Download of bekijk de voltooide app.Downloadinstructies.

Prerequisites

Database-engines

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

Troubleshooting

Als u een probleem ondervindt dat u niet kunt oplossen, vergelijkt u de code met het voltooide project. Een goede manier om hulp te krijgen is door een vraag te plaatsen op StackOverflow.com, met behulp van de ASP.NET Core-tag of de EF Core tag.

De voorbeeld-app

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 die in de zelfstudie zijn gemaakt.

Studentenindexpagina

Pagina Studenten bewerken

De gebruikersinterfacestijl van deze site is gebaseerd op de ingebouwde projectsjablonen. De focus van de zelfstudie ligt op het gebruik EF Core met ASP.NET Core, niet op het aanpassen van de gebruikersinterface.

Optioneel: het voorbeeld voor downloaden bouwen

Deze stap is optioneel. Het bouwen van de voltooide app wordt aanbevolen wanneer u problemen ondervindt die u niet kunt oplossen. Als u een probleem ondervindt dat u niet kunt oplossen, vergelijkt u de code met het voltooide project. Downloadinstructies.

Selecteer ContosoUniversity.csproj om het project te openen.

  • Bouw het project.
  • Voer in Package Manager Console (PMC) de volgende opdracht uit:
Update-Database

Voer het project uit om de database te seeden.

Het web-app-project 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 ContosoUniversity voor Projectnaam in. Het is belangrijk om precies deze naam te gebruiken, inclusief hoofdlettergevoeligheid, zodat elke namespace overeenkomt wanneer code wordt gekopieerd.
  4. Klik op Creëren.
  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.
    3. MakenNieuw ASP.NET Core Project dialoogvenster

De sitestijl instellen

Kopieer en plak de volgende code in het Pages/Shared/_Layout.cshtml bestand:

<!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-page="/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-page="/About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Departments/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; 2021 - Contoso University - <a asp-area="" asp-page="/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>

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

Het indelingsbestand stelt de sitekoptekst, voettekst en menu in. De voorgaande code brengt de volgende wijzigingen aan:

  • Elke voorkomst van 'ContosoUniversity' veranderd naar 'Contoso University'. Er zijn drie gebeurtenissen.
  • De Home en Privacy menu-items worden verwijderd.
  • Vermeldingen worden toegevoegd voor About, Students, Courses, Instructors en Afdelingen.

Vervang Pages/Index.cshtmlde inhoud van het bestand door de volgende code:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="row mb-auto">
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 mb-4 ">
                <p class="card-text">
                    Contoso University is a sample application that
                    demonstrates how to use Entity Framework Core in an
                    ASP.NET Core Razor Pages web app.
                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column position-static">
                <p class="card-text mb-auto">
                    You can build the application by following the steps in a series of tutorials.
                </p>
                <p>
                    <a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column">
                <p class="card-text mb-auto">
                    You can download the completed project from GitHub.
                </p>
                <p>
                    <a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
                </p>
            </div>
        </div>
    </div>
</div>

De voorgaande code vervangt de tekst over ASP.NET Core door tekst over deze app.

Voer de app uit om te controleren of de startpagina wordt weergegeven.

Het gegevensmodel

In de volgende secties wordt een gegevensmodel gemaakt:

Cursus-Enrollment-Student gegevensmodeldiagram

Een student kan zich inschrijven voor een willekeurig aantal cursussen en een cursus kan een willekeurig aantal studenten hebben ingeschreven.

De entiteit Student

Diagram van studententiteit

  • Maak een map Modellen in de projectmap.

  • Maak Models/Student.cs 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 wordt de primaire sleutelkolom van de databasetabel die overeenkomt met deze klasse. Interpreteert standaard EF Core een eigenschap met de naam ID of classnameID als de primaire sleutel. De alternatieve automatisch herkende naam voor de primaire sleutel van de Student klasse is StudentIDdus. Zie - Sleutels voor meer informatieEF Core.

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 Student entiteit alle Enrollment entiteiten die zijn gerelateerd aan die student. Als een rij Student in de database bijvoorbeeld twee gerelateerde inschrijvingsrijen heeft, bevat de Enrollments navigatie-eigenschap deze twee inschrijvingsentiteiten.

In de database is een inschrijvingsrij gerelateerd aan een rij Student als de StudentID kolom de id-waarde van de student bevat. Stel dat een rij Student id=1 heeft. Gerelateerde inschrijvingsrijen hebben StudentID = 1. StudentID is een vreemde sleutel in de tabel Inschrijving.

De Enrollments-eigenschap is als ICollection<Enrollment> gedefinieerd omdat er mogelijk meerdere gerelateerde ingeschreven entiteiten zijn. Andere verzamelingstypen kunnen worden gebruikt, zoals List<Enrollment> of HashSet<Enrollment>. Wanneer ICollection<Enrollment> wordt gebruikt, creëert EF Core standaard een HashSet<Enrollment> verzameling.

De entiteit Inschrijving

Diagram van inschrijvingsentiteit

Maak Models/Enrollment.cs met de volgende code:

using System.ComponentModel.DataAnnotations;

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; }
        [DisplayFormat(NullDisplayText = "No grade")]
        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. Voor een productiegegevensmodel kiezen veel ontwikkelaars één patroon en gebruiken ze dit consistent. In deze tutorial maakt men gebruik van beide om te illustreren dat beide werken. Het gebruiken van ID zonder classname maakt het eenvoudiger om bepaalde soorten wijzigingen in gegevensmodellen 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, dus de eigenschap bevat één Student entiteit.

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

EF Core interpreteert een eigenschap als een vreemde sleutel als deze de naam <navigation property name><primary key property name> heeft. Bijvoorbeeld, StudentID is de refererende sleutel voor de Student navigatie-eigenschap, aangezien de primaire sleutel van de Student entiteit ID is. Eigenschappen van refererende sleutels kunnen ook een naam <primary key property name>hebben. Omdat de primaire sleutel van de CourseID entiteit bijvoorbeeld Course isCourseID.

De entiteit Cursus

Diagram van cursusentiteit

Maak Models/Course.cs 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.

Met DatabaseGenerated het kenmerk kan de app de primaire sleutel opgeven in plaats van de database deze te laten genereren.

Bouw het project om te valideren dat er geen compilerfouten zijn.

Scaffold-pagina's voor leerlingen/studenten

In deze sectie wordt het hulpprogramma ASP.NET Core-scaffolding gebruikt om het volgende te genereren:

  • Een EF CoreDbContext klas. De context is de belangrijkste klasse die de Functionaliteit van Entity Framework coördineert voor een bepaald gegevensmodel. Het is afgeleid van de Microsoft.EntityFrameworkCore.DbContext klasse.
  • Razor pagina's die CRUD-bewerkingen (Create, Read, Update en Delete) voor de Student entiteit verwerken.
  • Maak een map Pagina's/leerlingen/studenten .
  • Klik in Solution Explorer met de rechtermuisknop op de map Pages/Students en selecteer Toevoegen>Nieuw ge-scaffolded item.
  • In het dialoogvenster Nieuw steigeronderdeel toevoegen:
    • Selecteer in het linkertabblad geïnstalleerde > algemene >Razor pagina's
    • Selecteer Razor pagina's met behulp van Entity Framework (CRUD)>Toevoegen.
  • In het dialoogvenster Pagina's toevoegen Razor met behulp van Entity Framework (CRUD):
    • Selecteer Student (ContosoUniversity.Models) in de vervolgkeuzelijst Modelklasse.
    • Selecteer in de rij Gegevenscontextklasse het + (plusteken).
      • Wijzig de naam van de gegevenscontext zodat deze eindigt SchoolContext in plaats ContosoUniversityContextvan . De bijgewerkte contextnaam: ContosoUniversity.Data.SchoolContext
      • Selecteer Toevoegen om de gegevenscontextklasse toe te voegen.
      • Selecteer Toevoegen om het dialoogvenster Pagina's toevoegen Razor te voltooien.

Als de scaffolding mislukt met de fout 'Install the package Microsoft.VisualStudio.Web.CodeGeneration.Design and try again.', voert u het hulpprogramma voor de scaffold opnieuw uit of kijk dan naar dit GitHub-probleem.

De volgende pakketten worden automatisch geïnstalleerd:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Als de voorgaande stap mislukt, bouwt u het project en probeert u de stap van het steigerelement opnieuw uit te voeren.

Het steigerproces:

  • Hiermee maakt u Razor pagina's in de map Pages/Students:
    • Create.cshtml en Create.cshtml.cs
    • Delete.cshtml en Delete.cshtml.cs
    • Details.cshtml en Details.cshtml.cs
    • Edit.cshtml en Edit.cshtml.cs
    • Index.cshtml en Index.cshtml.cs
  • Maakt Data/SchoolContext.cs.
  • Voegt de context toe aan afhankelijkheidsinjectie in Startup.cs.
  • Hiermee voegt u een databaseverbindingsreeks toe aan appsettings.json.

database-verbindingstekenreeks

Het hulpprogramma voor scaffolding genereert een verbindingsreeks in het appsettings.json bestand.

De verbindingsreeks geeft SQL Server LocalDB op:

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

LocalDB is een lichtgewicht versie van de SQL Server Express Database Engine en is bedoeld voor app-ontwikkeling, niet voor productiegebruik. LocalDB maakt standaard .mdf bestanden in de C:/Users/<user> map.

De databasecontextklasse bijwerken

De belangrijkste klasse die de functionaliteit voor een bepaald gegevensmodel coördineert EF Core , is de contextklasse van de database. De context is afgeleid van Microsoft.EntityFrameworkCore.DbContext. De context geeft aan welke entiteiten zijn opgenomen in het gegevensmodel. In dit project heeft de klasse de naam SchoolContext.

Werk Data/SchoolContext.cs bij met de volgende code:

using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;

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

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

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

De voorgaande code verandert van de enkelvoud DbSet<Student> Student in het meervoud DbSet<Student> Students. Om de Razor Pagina's-code overeen te laten komen met de nieuwe DBSet naam, voert u een globale wijziging door van: _context.Student. Aan: _context.Students.

Er zijn 8 voorkomens.

Omdat een entiteitsset meerdere entiteiten bevat, geven veel ontwikkelaars de voorkeur aan de DBSet eigenschapsnamen in meervoud.

De gemarkeerde code:

  • Hiermee maakt u een DbSet<TEntity> eigenschap voor elke entiteitsset. In EF Core terminologie:
    • Een entiteitsset komt meestal overeen met een databasetabel.
    • Een entiteit komt overeen met een rij in de tabel.
  • Roept OnModelCreating aan. OnModelCreating:
    • Wordt aangeroepen wanneer SchoolContext is geïnitialiseerd, maar voordat het model wordt beveiligd en gebruikt om de context te initialiseren.
    • Is vereist omdat de Student entiteit later in de instructies naar de andere entiteiten zal verwijzen.

Bouw het project om te controleren of er geen compilerfouten zijn.

Startup.cs

ASP.NET Core is gebouwd met afhankelijkheidsinjectie. Services zoals de SchoolContext services worden geregistreerd met afhankelijkheidsinjectie tijdens het opstarten van de app. Componenten die deze services vereisen, zoals Razor pagina's, ontvangen deze services via constructorparameters. De constructorcode die een databasecontextinstantie ophaalt, wordt verderop in de zelfstudie weergegeven.

Het hulpprogramma voor scaffolding registreerde automatisch de contextklasse met de container voor afhankelijkheidsinjectie.

De volgende gemarkeerde lijnen zijn toegevoegd door de scaffolder:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

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

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

Het uitzonderingsfilter voor de database toevoegen

Voeg AddDatabaseDeveloperPageExceptionFilter toe en UseMigrationsEndPoint zoals wordt weergegeven in de volgende code:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

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

    services.AddDatabaseDeveloperPageExceptionFilter();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseMigrationsEndPoint();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Voeg het NuGet-pakket Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore toe.

Voer in de Package Manager-console het volgende in om het NuGet-pakket toe te voegen:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore

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

De AddDatabaseDeveloperPageExceptionFilter biedt nuttige foutinformatie in de ontwikkelomgeving voor EF-migratiefouten.

De database maken

Werk Program.cs bij om de database te maken als deze niet bestaat:

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>();
                    context.Database.EnsureCreated();
                    // 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 EnsureCreated methode voert geen actie uit als er een database voor de context bestaat. Als er geen database bestaat, worden de database en het schema gemaakt. EnsureCreated maakt de volgende werkstroom mogelijk voor het verwerken van wijzigingen in gegevensmodellen:

  • Verwijder de database. Alle bestaande gegevens gaan verloren.
  • Wijzig het gegevensmodel. Voeg bijvoorbeeld een EmailAddress veld toe.
  • Voer de app uit.
  • EnsureCreated maakt een database met het nieuwe schema.

Deze werkstroom werkt vroeg in ontwikkeling wanneer het schema zich snel ontwikkelt, zolang gegevens niet hoeven te worden bewaard. De situatie verschilt wanneer gegevens die in de database zijn ingevoerd, moeten worden bewaard. Als dat het geval is, gebruik migraties.

Later in de reeks zelfstudies wordt de database die is aangemaakt door EnsureCreated verwijderd en vervolgens worden migraties gebruikt. Een database die wordt gemaakt door EnsureCreated , kan niet worden bijgewerkt met behulp van migraties.

De app testen

  • Voer de app uit.
  • Selecteer de koppeling Leerlingen/studenten en vervolgens Nieuwe maken.
  • Test de koppelingen Bewerken, Details en Verwijderen.

De database vullen met gegevens

Met de EnsureCreated methode wordt een lege database gemaakt. In deze sectie wordt code toegevoegd waarmee de database wordt gevuld met testgegevens.

Maak Data/DbInitializer.cs 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)
        {
            // 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("2019-09-01")},
                new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
                new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
            };

            context.Students.AddRange(students);
            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}
            };

            context.Courses.AddRange(courses);
            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},
            };

            context.Enrollments.AddRange(enrollments);
            context.SaveChanges();
        }
    }
}

De code controleert of er leerlingen/studenten zijn in de database. Als er geen leerlingen/studenten zijn, worden er testgegevens aan de database toegevoegd. Hiermee worden de testgegevens in matrices gemaakt in plaats List<T> van verzamelingen om de prestaties te optimaliseren.

  • Verwijder Program.cs uit de // regel in DbInitializer.Initialize.

      context.Database.EnsureCreated();
      DbInitializer.Initialize(context);
    
  • Stop de app als deze wordt uitgevoerd en voer de volgende opdracht uit in de Package Manager Console (PMC):

    Drop-Database -Confirm
    
    
  • Reageer met Y om de database te verwijderen.

  • Start de app opnieuw op.
  • Selecteer de pagina Leerlingen/studenten om de gezaaide gegevens weer te geven.

De database weergeven

  • Open SQL Server Object Explorer (SSOX) in het menu Beeld in Visual Studio.
  • Selecteer in SSOX de (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. De databasenaam wordt gegenereerd op basis van de contextnaam die u eerder hebt opgegeven, plus een streepje en een GUID.
  • Vouw het knooppunt Tabellen uit.
  • Klik met de rechtermuisknop op de tabel Student en klik op Gegevens weergeven om de kolommen weer te geven die zijn gemaakt en de rijen die zijn ingevoegd in de tabel.
  • Klik met de rechtermuisknop op de tabel Student en klik op Code weergeven om te zien hoe het Student model wordt toegewezen aan het Student tabelschema.

Asynchrone 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 bezet zijn terwijl ze niet werken 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. Hierdoor kan asynchrone code serverresources efficiënter worden gebruikt en kan de server zonder vertragingen meer verkeer verwerken.

Asynchrone code introduceert een kleine hoeveelheid overhead tijdens runtime. Voor lage-verkeersituaties is de impact op de prestaties te verwaarlozen, terwijl voor hoge-verkeersituaties de potentiële prestatieverbetering aanzienlijk is.

In de volgende code wordt het asynchrone trefwoord, Task de retourwaarde, await het trefwoord en ToListAsync de methode asynchroon uitgevoerd.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Het async trefwoord vertelt de compiler aan:
    • Callbacks genereren voor delen van de hoofdtekst van de methode.
    • Maak het taakobject dat wordt geretourneerd.
  • Het Task retourtype vertegenwoordigt doorlopend werk.
  • 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 Core:

  • Alleen instructies die ertoe leiden dat query's of opdrachten naar de database worden verzonden, worden asynchroon uitgevoerd. Dat omvat ToListAsync, SingleOrDefaultAsync, en FirstOrDefaultAsyncSaveChangesAsync. Het bevat geen uitspraken die alleen een IQueryable veranderen, zoals var students = context.Students.Where(s => s.LastName == "Davolio").
  • Een EF Core context is niet thread-veilig: probeer niet meerdere bewerkingen parallel uit te voeren.
  • Als u wilt profiteren van de prestatievoordelen van asynchrone code, controleert u of bibliotheekpakketten (zoals voor paging) asynchroon worden gebruikt als ze methoden aanroepen EF Core waarmee query's naar de database worden verzonden.

Zie Async Overview en Asynchroon programmeren met async en await voor meer informatie over asynchrone programmering in .NET.

Prestatieoverwegingen

Over het algemeen mag een webpagina geen willekeurig aantal rijen laden. Een query moet paginering of een beperkende benadering gebruiken. De voorgaande query kan bijvoorbeeld worden gebruikt Take om de geretourneerde rijen te beperken:

public async Task OnGetAsync()
{
    Student = await _context.Students.Take(10).ToListAsync();
}

Bij het opsommen van een grote tabel in een weergave kan een gedeeltelijk opgebouwd HTTP 200-antwoord worden geretourneerd als er een database-uitzondering optreedt tijdens de opsomming.

MaxModelBindingCollectionSize is standaard ingesteld op 1024. De volgende code stelt MaxModelBindingCollectionSize:

public void ConfigureServices(IServiceCollection services)
{
    var myMaxModelBindingCollectionSize = Convert.ToInt32(
                Configuration["MyMaxModelBindingCollectionSize"] ?? "100");

    services.Configure<MvcOptions>(options =>
           options.MaxModelBindingCollectionSize = myMaxModelBindingCollectionSize);

    services.AddRazorPages();

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

    services.AddDatabaseDeveloperPageExceptionFilter();
}

Zie Configuratie voor informatie over configuratie-instellingen, zoals MyMaxModelBindingCollectionSize.

Paging wordt verderop in de zelfstudie behandeld.

Zie Prestatieoverwegingen (EF) voor meer informatie.

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.

Volgende stappen

SQLite gebruiken voor ontwikkeling, SQL Server voor productie

Dit is de eerste in een reeks zelfstudies die laten zien hoe u Entity Framework (EF) Core gebruikt in een app ASP.NET Core Razor Pages . De handleidingen bouwen een website voor het fictieve "Contoso University". De site bevat functionaliteit zoals toelating van studenten, het maken van cursussen en docentopdrachten. In de tutorial wordt de code-first benadering gebruikt. Zie dit GitHub-probleem voor informatie over het volgen van deze zelfstudie met behulp van de eerste benadering van de database.

Download of bekijk de voltooide app.Downloadinstructies.

Prerequisites

Database-engines

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

De Visual Studio Code-instructies maken gebruik van SQLite, een platformoverschrijdende database-engine.

Als u ervoor kiest OM SQLite te gebruiken, downloadt en installeert u een hulpprogramma van derden voor het beheren en weergeven van een SQLite-database, zoals DB Browser voor SQLite.

Troubleshooting

Als u een probleem ondervindt dat u niet kunt oplossen, vergelijkt u de code met het voltooide project. Een goede manier om hulp te krijgen is door een vraag te plaatsen op StackOverflow.com, met behulp van de ASP.NET Core-tag of de EF Core tag.

De voorbeeld-app

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 die in de zelfstudie zijn gemaakt.

Studentenindexpagina

Pagina Studenten bewerken

De gebruikersinterfacestijl van deze site is gebaseerd op de ingebouwde projectsjablonen. De focus van de zelfstudie ligt op het gebruik van EF Core, niet op het aanpassen van de gebruikersinterface.

Volg de koppeling boven aan de pagina om de broncode voor het voltooide project op te halen. De map cu30 bevat de codebron voor de ASP.NET Core 3.0-versie van de zelfstudie. De bestanden die de status van de code voor tutorials 1-7 weerspiegelen, zijn te vinden in de map cu30snapshots.

De app uitvoeren nadat het voltooide project is gedownload:

  • Bouw het project.

  • Voer in Package Manager Console (PMC) de volgende opdracht uit:

    Update-Database
    
  • Voer het project uit om de database te seeden.

Het web-app-project maken

  • In het menu Bestand van Visual Studio, selecteer Nieuw>project.
  • Selecteer ASP.NET Core-webtoepassing.
  • Geef het project de naam ContosoUniversity. Het is belangrijk om deze exacte naam te gebruiken, inclusief hoofdlettergebruik, zodat de naamruimten overeenkomen wanneer code wordt gekopieerd en geplakt.
  • Selecteer .NET Core en ASP.NET Core 3.0 in de vervolgkeuzelijsten en selecteer vervolgens Webtoepassing.

De sitestijl instellen

Stel de koptekst, voettekst en het menu van de site in door het volgende bij te werken Pages/Shared/_Layout.cshtml:

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

  • Verwijder de Home en Privacy menu-items en voeg vermeldingen toe voor Info, Studenten, Cursussen, Instructeurs en Afdelingen.

De wijzigingen zijn gemarkeerd.

<!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-page="/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-page="/About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Departments/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; 2019 - Contoso University - <a asp-area="" asp-page="/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>

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

Vervang Pages/Index.cshtmlde inhoud van het bestand door de volgende code om de tekst over ASP.NET Core te vervangen door tekst over deze app:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="row mb-auto">
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 mb-4 ">
                <p class="card-text">
                    Contoso University is a sample application that
                    demonstrates how to use Entity Framework Core in an
                    ASP.NET Core Razor Pages web app.
                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column position-static">
                <p class="card-text mb-auto">
                    You can build the application by following the steps in a series of tutorials.
                </p>
                <p>
                    <a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column">
                <p class="card-text mb-auto">
                    You can download the completed project from GitHub.
                </p>
                <p>
                    <a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
                </p>
            </div>
        </div>
    </div>
</div>

Voer de app uit om te controleren of de startpagina wordt weergegeven.

Het gegevensmodel

In de volgende secties wordt een gegevensmodel gemaakt:

Cursus-Enrollment-Student gegevensmodeldiagram

Een student kan zich inschrijven voor een willekeurig aantal cursussen en een cursus kan een willekeurig aantal studenten hebben ingeschreven.

De entiteit Student

Diagram van studententiteit

  • Maak een map Modellen in de projectmap.

  • Maak Models/Student.cs 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 wordt de primaire sleutelkolom van de databasetabel die overeenkomt met deze klasse. Interpreteert standaard EF Core een eigenschap met de naam ID of classnameID als de primaire sleutel. De alternatieve automatisch herkende naam voor de primaire sleutel van de Student klasse is StudentIDdus. Zie - Sleutels voor meer informatieEF Core.

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 Student entiteit alle Enrollment entiteiten die zijn gerelateerd aan die student. Als een rij Student in de database bijvoorbeeld twee gerelateerde inschrijvingsrijen heeft, bevat de Enrollments navigatie-eigenschap deze twee inschrijvingsentiteiten.

In de database is een inschrijvingsrij gerelateerd aan een rij Student als de kolom StudentID de id-waarde van de student bevat. Stel dat een rij Student id=1 heeft. Gerelateerde inschrijvingsrijen hebben StudentID = 1. StudentID is een vreemde sleutel in de tabel Inschrijving.

De Enrollments-eigenschap is als ICollection<Enrollment> gedefinieerd omdat er mogelijk meerdere gerelateerde ingeschreven entiteiten zijn. U kunt andere verzamelingstypen gebruiken, zoals List<Enrollment> of HashSet<Enrollment>. Wanneer ICollection<Enrollment> wordt gebruikt, creëert EF Core standaard een HashSet<Enrollment> verzameling.

De entiteit Inschrijving

Diagram van inschrijvingsentiteit

Maak Models/Enrollment.cs 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 primaire sleutel. Deze entiteit gebruikt het classnameID patroon in plaats van ID zelf. Voor een productiegegevensmodel kiest u één patroon en gebruikt u dit consistent. In deze tutorial maakt men gebruik van beide om te illustreren dat beide werken. Het gebruiken van ID zonder classname maakt het eenvoudiger om bepaalde soorten wijzigingen in gegevensmodellen 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, dus de eigenschap bevat één Student entiteit.

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

EF Core interpreteert een eigenschap als een vreemde sleutel als deze de naam <navigation property name><primary key property name> heeft. Bijvoorbeeld, StudentID is de refererende sleutel voor de Student navigatie-eigenschap, aangezien de primaire sleutel van de Student entiteit ID is. Eigenschappen van refererende sleutels kunnen ook een naam <primary key property name>hebben. Omdat de primaire sleutel van de CourseID entiteit bijvoorbeeld Course isCourseID.

De entiteit Cursus

Diagram van cursusentiteit

Maak Models/Course.cs 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.

Met DatabaseGenerated het kenmerk kan de app de primaire sleutel opgeven in plaats van de database deze te laten genereren.

Bouw het project om te valideren dat er geen compilerfouten zijn.

Scaffold-pagina's voor leerlingen/studenten

In deze sectie gebruikt u het hulpprogramma ASP.NET Core-scaffolding om het volgende te genereren:

  • Een EF Corecontextklasse . De context is de belangrijkste klasse die de Functionaliteit van Entity Framework coördineert voor een bepaald gegevensmodel. Het is afgeleid van de Microsoft.EntityFrameworkCore.DbContext klasse.
  • Razor pagina's die CRUD-bewerkingen (Create, Read, Update en Delete) voor de Student entiteit verwerken.
  • Maak een map Leerlingen/studenten in de map Pagina's .
  • Klik in Solution Explorer met de rechtermuisknop op de map Pages/Students en selecteer Toevoegen>Nieuw ge-scaffolded item.
  • In het dialoogvenster Scaffold toevoegen, selecteer Razor Pagina's met behulp van Entity Framework (CRUD)>ADD.
  • In het dialoogvenster Pagina's toevoegen Razor met behulp van Entity Framework (CRUD):
    • Selecteer Student (ContosoUniversity.Models) in de vervolgkeuzelijst Modelklasse.
    • Selecteer in de rij Gegevenscontextklasse het + (plusteken).
    • Wijzig de naam van de gegevenscontext van ContosoUniversity.Models.ContosoUniversityContext in ContosoUniversity.Data.SchoolContext.
    • Selecteer Toevoegen.

De volgende pakketten worden automatisch geïnstalleerd:

  • Microsoft.VisualStudio.Web.CodeGeneration.Design
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.Extensions.Logging.Debug
  • Microsoft.EntityFrameworkCore.Tools

Als u een probleem hebt met de vorige stap, bouwt u het project opnieuw en probeert u de scaffold-stap opnieuw.

Het steigerproces:

  • Hiermee maakt u Razor pagina's in de map Pages/Students:
    • Create.cshtml en Create.cshtml.cs
    • Delete.cshtml en Delete.cshtml.cs
    • Details.cshtml en Details.cshtml.cs
    • Edit.cshtml en Edit.cshtml.cs
    • Index.cshtml en Index.cshtml.cs
  • Maakt Data/SchoolContext.cs.
  • Voegt de context toe aan afhankelijkheidsinjectie in Startup.cs.
  • Hiermee voegt u een databaseverbindingsreeks toe aan appsettings.json.

database-verbindingstekenreeks

Het appsettings.json bestand geeft de verbindingsreeks SQL Server LocalDB op.

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

LocalDB is een lichtgewicht versie van de SQL Server Express Database Engine en is bedoeld voor app-ontwikkeling, niet voor productiegebruik. LocalDB maakt standaard .mdf bestanden in de C:/Users/<user> map.

De databasecontextklasse bijwerken

De belangrijkste klasse die de functionaliteit voor een bepaald gegevensmodel coördineert EF Core , is de contextklasse van de database. De context is afgeleid van Microsoft.EntityFrameworkCore.DbContext. De context geeft aan welke entiteiten zijn opgenomen in het gegevensmodel. In dit project heeft de klasse de naam SchoolContext.

Werk Data/SchoolContext.cs bij met de volgende code:

using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;

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

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

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

Met de gemarkeerde code wordt een DbSet<TEntity> eigenschap gemaakt voor elke entiteitsset. In EF Core terminologie:

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

Omdat een entiteitsset meerdere entiteiten bevat, moeten de DBSet-eigenschappen meervoudsnamen zijn. Omdat het hulpprogramma voor scaffolding eenStudent DBSet heeft aangemaakt, wordt deze stap aangepast naar het meervoudStudents.

Als u de Razor paginacode wilt laten overeenkomen met de nieuwe DBSet-naam, moet u een globale wijziging aanbrengen in het hele project van _context.Student ._context.Students Er zijn 8 voorkomens.

Bouw het project om te controleren of er geen compilerfouten zijn.

Startup.cs

ASP.NET Core is gebouwd met afhankelijkheidsinjectie. Services (zoals de EF Core databasecontext) worden geregistreerd met afhankelijkheidsinjectie tijdens het opstarten van de toepassing. Onderdelen die deze services vereisen (zoals Razor Pagina's) ontvangen deze services via constructorparameters. De constructorcode die een databasecontextinstantie ophaalt, wordt verderop in de zelfstudie weergegeven.

Het hulpprogramma voor scaffolding registreerde automatisch de contextklasse met de container voor afhankelijkheidsinjectie.

  • In ConfigureServices zijn de gemarkeerde lijnen toegevoegd door de steigerbouwer.

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

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

De database maken

Werk Program.cs bij om de database te maken als deze niet bestaat:

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>();
                    context.Database.EnsureCreated();
                    // 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 EnsureCreated methode voert geen actie uit als er een database voor de context bestaat. Als er geen database bestaat, worden de database en het schema gemaakt. EnsureCreated maakt de volgende werkstroom mogelijk voor het verwerken van wijzigingen in gegevensmodellen:

  • Verwijder de database. Alle bestaande gegevens gaan verloren.
  • Wijzig het gegevensmodel. Voeg bijvoorbeeld een EmailAddress veld toe.
  • Voer de app uit.
  • EnsureCreated maakt een database met het nieuwe schema.

Deze werkstroom werkt goed vroeg in ontwikkeling wanneer het schema zich snel ontwikkelt, zolang u geen gegevens hoeft te bewaren. De situatie verschilt wanneer gegevens die in de database zijn ingevoerd, moeten worden bewaard. Als dat het geval is, gebruik migraties.

Later in de reeks zelfstudies verwijdert u de database die is gemaakt door EnsureCreated en gebruikt u in plaats daarvan migraties. Een database die wordt gemaakt door EnsureCreated , kan niet worden bijgewerkt met behulp van migraties.

De app testen

  • Voer de app uit.
  • Selecteer de koppeling Leerlingen/studenten en vervolgens Nieuwe maken.
  • Test de koppelingen Bewerken, Details en Verwijderen.

De database vullen met gegevens

Met de EnsureCreated methode wordt een lege database gemaakt. In deze sectie wordt code toegevoegd waarmee de database wordt gevuld met testgegevens.

Maak Data/DbInitializer.cs met de volgende code:

using ContosoUniversity.Data;
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("2019-09-01")},
                new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
                new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
            };

            context.Students.AddRange(students);
            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}
            };

            context.Courses.AddRange(courses);
            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},
            };

            context.Enrollments.AddRange(enrollments);
            context.SaveChanges();
        }
    }
}

De code controleert of er leerlingen/studenten zijn in de database. Als er geen leerlingen/studenten zijn, worden er testgegevens aan de database toegevoegd. Hiermee worden de testgegevens in matrices gemaakt in plaats List<T> van verzamelingen om de prestaties te optimaliseren.

  • Vervang Program.cs de EnsureCreated aanroep door een DbInitializer.Initialize aanroep:

    // context.Database.EnsureCreated();
    DbInitializer.Initialize(context);
    

Stop de app als deze wordt uitgevoerd en voer de volgende opdracht uit in de Package Manager Console (PMC):

Drop-Database
  • Start de app opnieuw op.

  • Selecteer de pagina Leerlingen/studenten om de gezaaide gegevens weer te geven.

De database weergeven

  • Open SQL Server Object Explorer (SSOX) in het menu Beeld in Visual Studio.
  • Selecteer in SSOX de (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. De databasenaam wordt gegenereerd op basis van de contextnaam die u eerder hebt opgegeven, plus een streepje en een GUID.
  • Vouw het knooppunt Tabellen uit.
  • Klik met de rechtermuisknop op de tabel Student en klik op Gegevens weergeven om de kolommen weer te geven die zijn gemaakt en de rijen die zijn ingevoegd in de tabel.
  • Klik met de rechtermuisknop op de tabel Student en klik op Code weergeven om te zien hoe het Student model wordt toegewezen aan het Student tabelschema.

Asynchrone 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. Hierdoor kan asynchrone code serverresources efficiënter worden gebruikt en kan de server zonder vertragingen meer verkeer verwerken.

Asynchrone code introduceert een kleine hoeveelheid overhead tijdens runtime. Voor lage-verkeersituaties is de impact op de prestaties te verwaarlozen, terwijl voor hoge-verkeersituaties de potentiële prestatieverbetering aanzienlijk is.

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

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Het async trefwoord vertelt de compiler aan:
    • Callbacks genereren voor delen van de hoofdtekst van de methode.
    • Maak het taakobject dat wordt geretourneerd.
  • Het Task<T> retourtype vertegenwoordigt doorlopend werk.
  • 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 Core:

  • Alleen instructies die ertoe leiden dat query's of opdrachten naar de database worden verzonden, worden asynchroon uitgevoerd. Dat omvat ToListAsync, SingleOrDefaultAsync, en FirstOrDefaultAsyncSaveChangesAsync. Het bevat geen uitspraken die alleen een IQueryable veranderen, zoals var students = context.Students.Where(s => s.LastName == "Davolio").
  • Een EF Core context is niet thread-veilig: probeer niet meerdere bewerkingen parallel uit te voeren.
  • Als u wilt profiteren van de prestatievoordelen van asynchrone code, controleert u of bibliotheekpakketten (zoals voor paging) asynchroon worden gebruikt als ze methoden aanroepen EF Core waarmee query's naar de database worden verzonden.

Zie Async Overview en Asynchroon programmeren met async en await voor meer informatie over asynchrone programmering in .NET.

Volgende stappen