Razor Stránky s Entity Framework Core v ASP.NET Core – kurz 1 z 8

Tom Dykstra, Jeremy Likness a Jon P Smith

Toto je první v řadě kurzů, které ukazují, jak používat Entity Framework (EF) Core v aplikaci ASP.NET Core Razor Pages . Kurzy vytvářejí web pro fiktivní univerzitu Contoso. Web obsahuje funkce, jako je přijetí studentů, vytvoření kurzu a zadání instruktora. Tento kurz používá první přístup kódu. Informace o sledování tohoto kurzu s využitím prvního přístupu k databázi najdete v tomto problému na GitHubu.

Stáhněte nebo zobrazte dokončenou aplikaci.Pokyny ke stažení

Požadavky

Databázové stroje

Pokyny pro Visual Studio používají SQL Server LocalDB, verzi SQL Serveru Express, která běží jenom ve Windows.

Řešení potíží

Pokud narazíte na problém, který nemůžete vyřešit, porovnejte kód s dokončeným projektem. Dobrý způsob, jak získat pomoc, je odesláním otázky na StackOverflow.com pomocí značky ASP.NET Core nebo značkyEF Core.

Ukázková aplikace

Aplikace vytvořená v těchto kurzech je základní web pro vysokoškoláky. Uživatelé můžou zobrazit a aktualizovat informace o studentech, kurzech a instruktorech. Tady je několik obrazovek vytvořených v kurzu.

Students Index page

Students Edit page

Styl uživatelského rozhraní tohoto webu je založený na předdefinovaných šablonách projektů. Tento kurz se zaměřuje na použití EF Core s ASP.NET Core, nikoli na přizpůsobení uživatelského rozhraní.

Volitelné: Sestavení ukázkového stažení

Tento krok je nepovinný. Sestavení dokončené aplikace se doporučuje, když máte problémy, které nemůžete vyřešit. Pokud narazíte na problém, který nemůžete vyřešit, porovnejte kód s dokončeným projektem. Pokyny ke stažení

Výběrem ContosoUniversity.csproj otevřete projekt.

  • Sestavte projekt.

  • V konzole Správce balíčků (PMC) spusťte následující příkaz:

    Update-Database
    

Spuštěním projektu zasadíte databázi.

Vytvoření projektu webové aplikace

  1. Spusťte Visual Studio 2022 a vyberte Vytvořit nový projekt.

    Create a new project from the start window

  2. V dialogovém okně Vytvořit nový projekt vyberte ASP.NET Core Web App a pak vyberte Další.

    Create an ASP.NET Core Web App

  3. V dialogovém okně Konfigurovat nový projekt zadejte ContosoUniversity název projektu. Je důležité pojmenovat projekt ContosoUniversity, včetně porovnávání velkých písmen, aby se obory názvů při kopírování a vkládání ukázkového kódu shodovaly.

  4. Vyberte Další.

  5. V dialogovém okně Další informace vyberte .NET 6.0 (dlouhodobá podpora) a pak vyberte Vytvořit.

    Additional information

Nastavení stylu webu

Zkopírujte a vložte do Pages/Shared/_Layout.cshtml souboru následující kód:

<!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>

Soubor rozložení nastaví záhlaví webu, zápatí a nabídku. Předchozí kód provede následující změny:

  • Každý výskyt "ContosoUniversity" na "Contoso University". Existují tři výskyty.
  • Položky Home nabídky a Privacy položky nabídky se odstraní.
  • Položky jsou přidány pro About, Students, Courses, Instructors a Departments.

Nahraďte Pages/Index.cshtmlobsah souboru následujícím kódem:

@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>

Předchozí kód nahradí text o ASP.NET Core textem o této aplikaci.

Spuštěním aplikace ověřte, že se zobrazí domovská stránka.

Datový model

Následující části vytvoří datový model:

Course-Enrollment-Student data model diagram

Student se může zaregistrovat do libovolného počtu kurzů a kurz může mít v něm zaregistrovaný libovolný počet studentů.

Entita Student

Student entity diagram

  • Ve složce projektu vytvořte složku Models .
  • Vytvořte Models/Student.cs pomocí následujícího kódu:
    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; }
        }
    }
    

Vlastnost ID se stane sloupcem primárního klíče v tabulce databáze, která odpovídá této třídě. Ve výchozím nastavení interpretuje vlastnost, EF Core která je pojmenovaná ID nebo classnameID jako primární klíč. Proto je alternativou automaticky rozpoznaný název primárního Student klíče StudentIDtřídy . Další informace najdete v tématu EF Core – Klíče.

Vlastnost Enrollments je navigační vlastnost. Vlastnosti navigace obsahují další entity, které souvisejí s touto entitou. V tomto případě Enrollments vlastnost Student entity obsahuje všechny Enrollment entity, které se vztahují k tomuto studentu. Pokud má například řádek Student v databázi dva související řádky registrace, Enrollments navigační vlastnost obsahuje tyto dvě entity registrace.

V databázi se řádek Registrace vztahuje k řádku Student, pokud jeho StudentID sloupec obsahuje hodnotu ID studenta. Předpokládejme například, že řádek Student má ID=1. Související řádky registrace budou mít StudentID hodnotu = 1. StudentIDje cizí klíč v tabulce Registrace.

Vlastnost je definována Enrollments , protože ICollection<Enrollment> může existovat více souvisejících entit registrace. Lze použít jiné typy kolekcí, například List<Enrollment> .HashSet<Enrollment> Při ICollection<Enrollment> použití EF Core vytvoří kolekci HashSet<Enrollment> ve výchozím nastavení.

Entita Registrace

Enrollment entity diagram

Vytvořte Models/Enrollment.cs pomocí následujícího kódu:

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; }
    }
}

Vlastnost EnrollmentID je primární klíč; tato entita používá classnameID vzor místo ID sebe sama. V případě produkčního datového modelu si mnoho vývojářů zvolí jeden vzor a konzistentně ho použije. V tomto kurzu se obě používají k ilustraci toho, že obě fungují. Použití ID bez classname usnadnění implementace některých druhů změn datového modelu.

Vlastnost Grade je .enum Otazník za Grade deklaraci typu označuje, že Grade vlastnost je nullable. Známka, která má hodnotu null, se liší od nulové známky – hodnota null znamená, že známka není známa nebo ještě nebyla přiřazena.

Vlastnost StudentID je cizí klíč a odpovídající navigační vlastnost je Student. Entita Enrollment je přidružená k jedné Student entitě, takže vlastnost obsahuje jednu Student entitu.

Vlastnost CourseID je cizí klíč a odpovídající navigační vlastnost je Course. Entita Enrollment je přidružená k jedné Course entitě.

EF Core interpretuje vlastnost jako cizí klíč, pokud je pojmenovaná <navigation property name><primary key property name>. Je to napříkladStudentID cizí klíč pro Student navigační vlastnost, protože Student primární klíč entity je ID. Vlastnosti cizího klíče lze také pojmenovat <primary key property name>. Například vzhledem k tomu, CourseID že Course primární klíč entity je CourseID.

Entita Course

Course entity diagram

Vytvořte Models/Course.cs pomocí následujícího kódu:

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; }
    }
}

Vlastnost Enrollments je navigační vlastnost. Entita Course může souviset s libovolným počtem Enrollment entit.

Atribut DatabaseGenerated umožňuje aplikaci místo vygenerování databáze zadat primární klíč.

Sestavte aplikaci. Kompilátor vygeneruje několik upozornění na způsob null zpracování hodnot. Další informace najdete v tomto problému Na GitHubu, odkazových typech s možnou hodnotou Null a Kurz: Záměr návrhu jasněji vyjádřete s odkazovými typy s možnou hodnotou null a nenulovou hodnotou.

Chcete-li odstranit upozornění z odkazových typů s možnou ContosoUniversity.csproj hodnotou null, odeberte ze souboru následující řádek:

<Nullable>enable</Nullable>

Modul generování uživatelského rozhraní v současné době nepodporuje odkazové typy s možnou hodnotou null, a proto ani modely použité v generování není možné.

Odeberte poznámku typu odkazu s možnou ? hodnotou null, public string? RequestId { get; set; }Pages/Error.cshtml.cs aby se projekt sestavil bez upozornění kompilátoru.

Vygenerované stránky studentů

V této části se k vygenerování používá nástroj pro generování uživatelského rozhraní ASP.NET Core:

  • Třída EF CoreDbContext . Kontext je hlavní třída, která koordinuje funkce Entity Framework pro daný datový model. Odvozuje z Microsoft.EntityFrameworkCore.DbContext třídy.
  • Razor stránky, které zpracovávají operace vytvoření, čtení, aktualizace a odstranění (CRUD) pro entitu Student .
  • Vytvořte složku Pages/Students .
  • V Průzkumník řešení klikněte pravým tlačítkem na složku Pages/Students a vyberte Přidat>novou vygenerovanou položku.
  • V dialogovém okně Přidat novou položku uživatelského rozhraní:
    • Na levé kartě vyberte Nainstalované > společné >Razor stránky.
    • Vyberte Razor stránky pomocí entity Framework (CRUD)>ADD.
  • V dialogovém okně Přidat Razor stránky pomocí entity Framework (CRUD):
    • V rozevíracím seznamu Třída modelu vyberte Student (ContosoUniversity.Models).
    • V řádku třídy kontextu dat vyberte znaménko + (plus).
      • Změňte název kontextu dat tak, aby končil SchoolContext místo ContosoUniversityContext. Aktualizovaný název kontextu: ContosoUniversity.Data.SchoolContext
      • Výběrem možnosti Přidat dokončíte přidání třídy kontextu dat.
      • Výběrem možnosti Přidat dokončete dialogové okno Přidat Razor stránky .

Automaticky se nainstalují následující balíčky:

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

Pokud předchozí krok selže, sestavte projekt a zopakujte krok generování.

Proces generování uživatelského rozhraní:

  • Vytvoří Razor stránky ve složce Pages/Students :
    • Create.cshtml a Create.cshtml.cs
    • Delete.cshtml a Delete.cshtml.cs
    • Details.cshtml a Details.cshtml.cs
    • Edit.cshtml a Edit.cshtml.cs
    • Index.cshtml a Index.cshtml.cs
  • Vytvoří Data/SchoolContext.cs.
  • Přidá kontext do injektáže závislostí v Program.cssouboru .
  • Přidá databázi připojovací řetězec do appsettings.json.

Připojovací řetězec databáze

Nástroj pro generování uživatelského rozhraní vygeneruje v souboru připojovací řetězecappsettings.json.

Připojovací řetězec určuje SQL Server LocalDB:

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

LocalDB je zjednodušená verze databázového stroje SQL Server Express a je určená pro vývoj aplikací, nikoli pro produkční použití. Ve výchozím nastavení vytvoří LocalDB soubory .mdf v C:/Users/<user> adresáři.

Aktualizace třídy kontextu databáze

Hlavní třída, která koordinuje EF Core funkce pro daný datový model, je třída kontextu databáze. Kontext je odvozen z Microsoft.EntityFrameworkCore.DbContext. Kontext určuje, které entity jsou součástí datového modelu. V tomto projektu má třída název SchoolContext.

Aktualizujte Data/SchoolContext.cs následujícím kódem:

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");
        }
    }
}

Předchozí kód se změní z jednotného čísla DbSet<Student> Student na množné číslo DbSet<Student> Students. Pokud chcete, aby Razor kód Stránky odpovídal novému DBSet názvu, proveďte globální změnu z: _context.Student. do: _context.Students.

Existuje 8 výskytů.

Vzhledem k tomu, že sada entit obsahuje více entit, mnoho vývojářů dává přednost DBSet názvům vlastností v množném čísle.

Zvýrazněný kód:

  • Vytvoří DbSet<TEntity> vlastnost pro každou sadu entit. V EF Core terminologii:
    • Sada entit obvykle odpovídá databázové tabulce.
    • Entita odpovídá řádku v tabulce.
  • Zavolá metodu OnModelCreating. OnModelCreating:
    • Volá se při SchoolContext inicializaci, ale před uzamčením modelu a jeho inicializací se používá k inicializaci kontextu.
    • Je vyžadováno, protože v pozdější části kurzu Student bude mít entita odkazy na ostatní entity.

Doufáme, že tento problém vyřešíme v budoucí verzi.

Program.cs

ASP.NET Core se sestavuje pomocí injektáže závislostí. Služby, jako SchoolContext je například injektáž závislostí, se registrují během spuštění aplikace. Komponenty, které vyžadují tyto služby, například Razor Stránky, jsou poskytovány prostřednictvím parametrů konstruktoru. Kód konstruktoru, který získá instanci kontextu databáze, se zobrazí později v kurzu.

Nástroj pro generování uživatelského rozhraní automaticky zaregistroval třídu kontextu s kontejnerem injektáže závislostí.

Následující zvýrazněné řádky přidal 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")));

Název připojovací řetězec se předává kontextu voláním metody na objektuDbContextOptions. Pro místní vývoj načte konfigurační systém ASP.NET Core připojovací řetězec ze appsettings.json souboru.appsettings.Development.json

Přidání filtru výjimek databáze

Přidejte AddDatabaseDeveloperPageExceptionFilter a UseMigrationsEndPoint jak je znázorněno v následujícím kódu:

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();
}

Přidejte balíček NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.

V konzole Správce balíčků zadejte následující příkaz, který přidá balíček NuGet:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore

Balíček Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet poskytuje ASP.NET middlewaru Core pro chybové stránky Entity Framework Core. Tento middleware pomáhá zjišťovat a diagnostikovat chyby při migracích Entity Framework Core.

Poskytuje AddDatabaseDeveloperPageExceptionFilter užitečné informace o chybách chyb ve vývojovém prostředí pro chyby migrace EF.

Vytvoření databáze

Aktualizujte Program.cs databázi, pokud neexistuje:

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();

Metoda EnsureCreated neprobíná žádnou akci, pokud existuje databáze pro kontext. Pokud žádná databáze neexistuje, vytvoří databázi a schéma. EnsureCreated umožňuje následující pracovní postup pro zpracování změn datového modelu:

  • Odstraňte databázi. Všechna existující data se ztratí.
  • Změňte datový model. Můžete například přidat EmailAddress pole.
  • Spustit aplikaci.
  • EnsureCreated vytvoří databázi s novým schématem.

Tento pracovní postup funguje v rané fázi vývoje, když se schéma rychle vyvíjí, pokud data nemusí být zachována. Situace se liší, když je potřeba zachovat data zadaná do databáze. V takovém případě použijte migrace.

Později v sérii kurzů se databáze odstraní, kterou vytvořila EnsureCreated a migrace se použije. Databázi vytvořenou pomocí EnsureCreated migrací nejde aktualizovat.

Otestování aplikace

  • Spustit aplikaci.
  • Vyberte odkaz Studenti a pak vytvořte nový.
  • Otestujte odkazy Upravit, Podrobnosti a Odstranit.

Počáteční hodnota databáze

Metoda EnsureCreated vytvoří prázdnou databázi. Tato část přidá kód, který naplní databázi testovacími daty.

Vytvořte Data/DbInitializer.cs pomocí následujícího kódu:

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();
        }
    }
}

Kód zkontroluje, jestli v databázi nejsou žádní studenti. Pokud nejsou žádní studenti, přidá do databáze testovací data. Vytvoří testovací data v polích místo List<T> kolekcí pro optimalizaci výkonu.

  • V Program.cs, odebrat // z DbInitializer.Initialize řádku:
using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    var context = services.GetRequiredService<SchoolContext>();
    context.Database.EnsureCreated();
    DbInitializer.Initialize(context);
}
  • Pokud je aplikace spuštěná, zastavte ji a v konzole Správce balíčků (PMC) spusťte následující příkaz:

    Drop-Database -Confirm
    
    
  • Odpovězte na Y odstranění databáze.

  • Restartujte aplikaci.
  • Výběrem stránky Studenti zobrazíte počáteční data.

Zobrazení databáze

  • V nabídce Zobrazit v sadě Visual Studio otevřete SQL Server Průzkumník objektů (SSOX).
  • V nástroji SSOX vyberte (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Název databáze se vygeneruje z názvu kontextu, který jste zadali dříve, a navíc pomlčku a identifikátor GUID.
  • Rozbalte uzel Tabulky.
  • Klikněte pravým tlačítkem myši na tabulku Student a kliknutím na Zobrazit data zobrazte sloupce vytvořené a řádky vložené do tabulky.
  • Klikněte pravým tlačítkem myši na tabulku Student a kliknutím na Zobrazit kód zobrazte, jak se Student model mapuje na Student schéma tabulky.

Asynchronní metody EF ve webových aplikacích ASP.NET Core

Asynchronní programování je výchozí režim pro ASP.NET Core a EF Core.

Webový server má k dispozici omezený počet vláken a v situacích s vysokým zatížením se můžou používat všechna dostupná vlákna. V takovém případě nemůže server zpracovat nové požadavky, dokud se vlákna nevysadí. V synchronním kódu může být mnoho vláken svázané, zatímco nefungují, protože čekají na dokončení vstupně-výstupních operací. Když proces čeká na dokončení vstupně-výstupních operací, v asynchronním kódu se jeho vlákno uvolní, aby server používal ke zpracování dalších požadavků. V důsledku toho asynchronní kód umožňuje efektivnější použití serverových prostředků a server dokáže zpracovat větší provoz bez zpoždění.

Asynchronní kód zavádí v době běhu malé režijní náklady. U situací s nízkým provozem je dosažení výkonu zanedbatelné, zatímco u vysokých dopravních situací je potenciální zlepšení výkonu podstatné.

V následujícím kódu asynchronní klíčové slovo, Task návratová hodnota, await klíčové slovo a ToListAsync metoda vytvoří kód asynchronně.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Klíčové async slovo říká kompilátoru, aby:
    • Vygenerujte zpětná volání pro části těla metody.
    • Vytvořte vrácený objekt Task .
  • Návratový Task typ představuje probíhající práci.
  • Klíčové await slovo způsobí, že kompilátor rozdělí metodu do dvou částí. První část končí operací, která se spouští asynchronně. Druhá část se vloží do metody zpětného volání, která se volá při dokončení operace.
  • ToListAsync je asynchronní verze ToList metody rozšíření.

Při psaní asynchronního kódu, který používá EF Core:

  • Asynchronně se spustí pouze příkazy, které způsobují odeslání dotazů nebo příkazů do databáze. To zahrnuje ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsynca SaveChangesAsync. Neobsahuje příkazy, které jen mění , IQueryablenapříklad var students = context.Students.Where(s => s.LastName == "Davolio").
  • Kontext EF Core není bezpečný pro vlákno: Nepokoušejte se paralelně provádět více operací.
  • Pokud chcete využít výhod výkonu asynchronního kódu, ověřte, že balíčky knihoven (například pro stránkování) používají asynchronní, pokud volají EF Core metody, které odesílají dotazy do databáze.

Další informace o asynchronním programování v .NET naleznete v tématu Přehled asynchronního a asynchronního programování pomocí asynchronního a await.

Upozorňující

Asynchronní implementace Microsoft.Data.SqlClient obsahuje některé známé problémy (#593, #601 a další). Pokud dochází k neočekávaným problémům s výkonem, zkuste místo toho použít spuštění příkazu synchronizace, zejména při práci s velkými textovými nebo binárními hodnotami.

Důležité informace o výkonu

Obecně platí, že webová stránka by neměla načítat libovolný počet řádků. Dotaz by měl používat stránkování nebo omezený přístup. Předchozí dotaz může například použít Take k omezení vrácených řádků:

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

Výčet velké tabulky v zobrazení by mohl vrátit částečně sestavenou odpověď HTTP 200, pokud dojde k výčtu výjimky databáze.

Stránkování se zabývá později v tomto kurzu.

Další informace najdete v tématu Důležité informace o výkonu (EF).

Další kroky

Použití SQLite pro vývoj, SQL Server pro produkční prostředí

Toto je první v řadě kurzů, které ukazují, jak používat Entity Framework (EF) Core v aplikaci ASP.NET Core Razor Pages . Kurzy vytvářejí web pro fiktivní univerzitu Contoso. Web obsahuje funkce, jako je přijetí studentů, vytvoření kurzu a zadání instruktora. Tento kurz používá první přístup kódu. Informace o sledování tohoto kurzu s využitím prvního přístupu k databázi najdete v tomto problému na GitHubu.

Stáhněte nebo zobrazte dokončenou aplikaci.Pokyny ke stažení

Požadavky

Databázové stroje

Pokyny pro Visual Studio používají SQL Server LocalDB, verzi SQL Serveru Express, která běží jenom ve Windows.

Řešení potíží

Pokud narazíte na problém, který nemůžete vyřešit, porovnejte kód s dokončeným projektem. Dobrý způsob, jak získat pomoc, je odesláním otázky na StackOverflow.com pomocí značky ASP.NET Core nebo značkyEF Core.

Ukázková aplikace

Aplikace vytvořená v těchto kurzech je základní web pro vysokoškoláky. Uživatelé můžou zobrazit a aktualizovat informace o studentech, kurzech a instruktorech. Tady je několik obrazovek vytvořených v kurzu.

Students Index page

Students Edit page

Styl uživatelského rozhraní tohoto webu je založený na předdefinovaných šablonách projektů. Tento kurz se zaměřuje na použití EF Core s ASP.NET Core, nikoli na přizpůsobení uživatelského rozhraní.

Volitelné: Sestavení ukázkového stažení

Tento krok je nepovinný. Sestavení dokončené aplikace se doporučuje, když máte problémy, které nemůžete vyřešit. Pokud narazíte na problém, který nemůžete vyřešit, porovnejte kód s dokončeným projektem. Pokyny ke stažení

Výběrem ContosoUniversity.csproj otevřete projekt.

  • Sestavte projekt.
  • V konzole Správce balíčků (PMC) spusťte následující příkaz:
Update-Database

Spuštěním projektu zasadíte databázi.

Vytvoření projektu webové aplikace

  1. Spusťte Visual Studio a vyberte Vytvořit nový projekt.
  2. V dialogovém okně Vytvořit nový projekt vyberte ASP.NET Další webová aplikace>Core.
  3. V dialogovém okně Konfigurovat nový projekt zadejte ContosoUniversity název projektu. Je důležité použít tento přesný název včetně velkých písmen, takže se každý z nich namespace shoduje při zkopírování kódu.
  4. Vyberte Vytvořit.
  5. V dialogovém okně Vytvořit novou webovou aplikaci ASP.NET Core vyberte:
    1. .NET Core a ASP.NET Core 5.0 v rozevíracích sadě
    2. ASP.NET Core Web App.
    3. VytvořitNew ASP.NET Core Project dialog

Nastavení stylu webu

Zkopírujte a vložte do Pages/Shared/_Layout.cshtml souboru následující kód:

<!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>

Soubor rozložení nastaví záhlaví webu, zápatí a nabídku. Předchozí kód provede následující změny:

  • Každý výskyt "ContosoUniversity" na "Contoso University". Existují tři výskyty.
  • Položky Home nabídky a Privacy položky nabídky se odstraní.
  • Položky jsou přidány pro About, Students, Courses, Instructors a Departments.

Nahraďte Pages/Index.cshtmlobsah souboru následujícím kódem:

@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>

Předchozí kód nahradí text o ASP.NET Core textem o této aplikaci.

Spuštěním aplikace ověřte, že se zobrazí domovská stránka.

Datový model

Následující části vytvoří datový model:

Course-Enrollment-Student data model diagram

Student se může zaregistrovat do libovolného počtu kurzů a kurz může mít v něm zaregistrovaný libovolný počet studentů.

Entita Student

Student entity diagram

  • Ve složce projektu vytvořte složku Models .

  • Vytvořte Models/Student.cs pomocí následujícího kódu:

    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; }
        }
    }
    

Vlastnost ID se stane sloupcem primárního klíče v tabulce databáze, která odpovídá této třídě. Ve výchozím nastavení interpretuje vlastnost, EF Core která je pojmenovaná ID nebo classnameID jako primární klíč. Proto je alternativou automaticky rozpoznaný název primárního Student klíče StudentIDtřídy . Další informace najdete v tématu EF Core – Klíče.

Vlastnost Enrollments je navigační vlastnost. Vlastnosti navigace obsahují další entity, které souvisejí s touto entitou. V tomto případě Enrollments vlastnost Student entity obsahuje všechny Enrollment entity, které se vztahují k tomuto studentu. Pokud má například řádek Student v databázi dva související řádky registrace, Enrollments navigační vlastnost obsahuje tyto dvě entity registrace.

V databázi se řádek Registrace vztahuje k řádku Student, pokud jeho StudentID sloupec obsahuje hodnotu ID studenta. Předpokládejme například, že řádek Student má ID=1. Související řádky registrace budou mít StudentID hodnotu = 1. StudentIDje cizí klíč v tabulce Registrace.

Vlastnost je definována Enrollments , protože ICollection<Enrollment> může existovat více souvisejících entit registrace. Lze použít jiné typy kolekcí, například List<Enrollment> .HashSet<Enrollment> Při ICollection<Enrollment> použití EF Core vytvoří kolekci HashSet<Enrollment> ve výchozím nastavení.

Entita Registrace

Enrollment entity diagram

Vytvořte Models/Enrollment.cs pomocí následujícího kódu:

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; }
    }
}

Vlastnost EnrollmentID je primární klíč; tato entita používá classnameID vzor místo ID sebe sama. V případě produkčního datového modelu si mnoho vývojářů zvolí jeden vzor a konzistentně ho použije. V tomto kurzu se obě používají k ilustraci toho, že obě fungují. Použití ID bez classname usnadnění implementace některých druhů změn datového modelu.

Vlastnost Grade je .enum Otazník za Grade deklaraci typu označuje, že Grade vlastnost je nullable. Známka, která má hodnotu null, se liší od nulové známky – hodnota null znamená, že známka není známa nebo ještě nebyla přiřazena.

Vlastnost StudentID je cizí klíč a odpovídající navigační vlastnost je Student. Entita Enrollment je přidružená k jedné Student entitě, takže vlastnost obsahuje jednu Student entitu.

Vlastnost CourseID je cizí klíč a odpovídající navigační vlastnost je Course. Entita Enrollment je přidružená k jedné Course entitě.

EF Core interpretuje vlastnost jako cizí klíč, pokud je pojmenovaná <navigation property name><primary key property name>. Je to napříkladStudentID cizí klíč pro Student navigační vlastnost, protože Student primární klíč entity je ID. Vlastnosti cizího klíče lze také pojmenovat <primary key property name>. Například vzhledem k tomu, CourseID že Course primární klíč entity je CourseID.

Entita Course

Course entity diagram

Vytvořte Models/Course.cs pomocí následujícího kódu:

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; }
    }
}

Vlastnost Enrollments je navigační vlastnost. Entita Course může souviset s libovolným počtem Enrollment entit.

Atribut DatabaseGenerated umožňuje aplikaci místo vygenerování databáze zadat primární klíč.

Sestavte projekt, abyste ověřili, že nedošlo k žádným chybám kompilátoru.

Vygenerované stránky studentů

V této části se k vygenerování používá nástroj pro generování uživatelského rozhraní ASP.NET Core:

  • Třída EF CoreDbContext . Kontext je hlavní třída, která koordinuje funkce Entity Framework pro daný datový model. Odvozuje z Microsoft.EntityFrameworkCore.DbContext třídy.
  • Razor stránky, které zpracovávají operace vytvoření, čtení, aktualizace a odstranění (CRUD) pro entitu Student .
  • Vytvořte složku Pages/Students .
  • V Průzkumník řešení klikněte pravým tlačítkem na složku Pages/Students a vyberte Přidat>novou vygenerovanou položku.
  • V dialogovém okně Přidat novou položku uživatelského rozhraní:
    • Na levé kartě vyberte Nainstalované > společné >Razor stránky.
    • Vyberte Razor stránky pomocí entity Framework (CRUD)>ADD.
  • V dialogovém okně Přidat Razor stránky pomocí entity Framework (CRUD):
    • V rozevíracím seznamu Třída modelu vyberte Student (ContosoUniversity.Models).
    • V řádku třídy kontextu dat vyberte znaménko + (plus).
      • Změňte název kontextu dat tak, aby končil SchoolContext místo ContosoUniversityContext. Aktualizovaný název kontextu: ContosoUniversity.Data.SchoolContext
      • Výběrem možnosti Přidat dokončíte přidání třídy kontextu dat.
      • Výběrem možnosti Přidat dokončete dialogové okno Přidat Razor stránky .

Pokud generování uživatelského rozhraní selže s chybou 'Install the package Microsoft.VisualStudio.Web.CodeGeneration.Design and try again.', spusťte znovu nástroj pro generování uživatelského rozhraní nebo se podívejte na tento problém na GitHubu.

Automaticky se nainstalují následující balíčky:

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

Pokud předchozí krok selže, sestavte projekt a zopakujte krok generování.

Proces generování uživatelského rozhraní:

  • Vytvoří Razor stránky ve složce Pages/Students :
    • Create.cshtml a Create.cshtml.cs
    • Delete.cshtml a Delete.cshtml.cs
    • Details.cshtml a Details.cshtml.cs
    • Edit.cshtml a Edit.cshtml.cs
    • Index.cshtml a Index.cshtml.cs
  • Vytvoří Data/SchoolContext.cs.
  • Přidá kontext do injektáže závislostí v Startup.cssouboru .
  • Přidá databázi připojovací řetězec do appsettings.json.

Připojovací řetězec databáze

Nástroj pro generování uživatelského rozhraní vygeneruje v souboru připojovací řetězecappsettings.json.

Připojovací řetězec určuje SQL Server LocalDB:

{
  "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 je zjednodušená verze databázového stroje SQL Server Express a je určená pro vývoj aplikací, nikoli pro produkční použití. Ve výchozím nastavení vytvoří LocalDB soubory .mdf v C:/Users/<user> adresáři.

Aktualizace třídy kontextu databáze

Hlavní třída, která koordinuje EF Core funkce pro daný datový model, je třída kontextu databáze. Kontext je odvozen z Microsoft.EntityFrameworkCore.DbContext. Kontext určuje, které entity jsou součástí datového modelu. V tomto projektu má třída název SchoolContext.

Aktualizujte Data/SchoolContext.cs následujícím kódem:

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");
        }
    }
}

Předchozí kód se změní z jednotného čísla DbSet<Student> Student na množné číslo DbSet<Student> Students. Pokud chcete, aby Razor kód Stránky odpovídal novému DBSet názvu, proveďte globální změnu z: _context.Student. do: _context.Students.

Existuje 8 výskytů.

Vzhledem k tomu, že sada entit obsahuje více entit, mnoho vývojářů dává přednost DBSet názvům vlastností v množném čísle.

Zvýrazněný kód:

  • Vytvoří DbSet<TEntity> vlastnost pro každou sadu entit. V EF Core terminologii:
    • Sada entit obvykle odpovídá databázové tabulce.
    • Entita odpovídá řádku v tabulce.
  • Zavolá metodu OnModelCreating. OnModelCreating:
    • Volá se při SchoolContext inicializaci, ale před uzamčením modelu a jeho inicializací se používá k inicializaci kontextu.
    • Je vyžadováno, protože v pozdější části kurzu Student bude mít entita odkazy na ostatní entity.

Sestavte projekt, abyste ověřili, že nedošlo k žádným chybám kompilátoru.

Startup.cs

ASP.NET Core se sestavuje pomocí injektáže závislostí. Služby, jako SchoolContext je například injektáž závislostí, se registrují během spuštění aplikace. Komponenty, které vyžadují tyto služby, například Razor Stránky, jsou poskytovány prostřednictvím parametrů konstruktoru. Kód konstruktoru, který získá instanci kontextu databáze, se zobrazí později v kurzu.

Nástroj pro generování uživatelského rozhraní automaticky zaregistroval třídu kontextu s kontejnerem injektáže závislostí.

Následující zvýrazněné řádky přidal scaffolder:

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

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

Název připojovací řetězec se předává kontextu voláním metody na objektuDbContextOptions. V případě místního vývoje načte konfigurační systém ASP.NET Core připojovací řetězec ze appsettings.json souboru.

Přidání filtru výjimek databáze

Přidejte AddDatabaseDeveloperPageExceptionFilter a UseMigrationsEndPoint jak je znázorněno v následujícím kódu:

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();
    });
}

Přidejte balíček NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.

V konzole Správce balíčků zadejte následující příkaz, který přidá balíček NuGet:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore

Balíček Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet poskytuje ASP.NET middlewaru Core pro chybové stránky Entity Framework Core. Tento middleware pomáhá zjišťovat a diagnostikovat chyby při migracích Entity Framework Core.

Poskytuje AddDatabaseDeveloperPageExceptionFilter užitečné informace o chybách chyb ve vývojovém prostředí pro chyby migrace EF.

Vytvoření databáze

Aktualizujte Program.cs databázi, pokud neexistuje:

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>();
                });
    }
}

Metoda EnsureCreated neprobíná žádnou akci, pokud existuje databáze pro kontext. Pokud žádná databáze neexistuje, vytvoří databázi a schéma. EnsureCreated umožňuje následující pracovní postup pro zpracování změn datového modelu:

  • Odstraňte databázi. Všechna existující data se ztratí.
  • Změňte datový model. Můžete například přidat EmailAddress pole.
  • Spustit aplikaci.
  • EnsureCreated vytvoří databázi s novým schématem.

Tento pracovní postup funguje v rané fázi vývoje, když se schéma rychle vyvíjí, pokud data nemusí být zachována. Situace se liší, když je potřeba zachovat data zadaná do databáze. V takovém případě použijte migrace.

Později v sérii kurzů se databáze odstraní, kterou vytvořila EnsureCreated a migrace se použije. Databázi vytvořenou pomocí EnsureCreated migrací nejde aktualizovat.

Otestování aplikace

  • Spustit aplikaci.
  • Vyberte odkaz Studenti a pak vytvořte nový.
  • Otestujte odkazy Upravit, Podrobnosti a Odstranit.

Počáteční hodnota databáze

Metoda EnsureCreated vytvoří prázdnou databázi. Tato část přidá kód, který naplní databázi testovacími daty.

Vytvořte Data/DbInitializer.cs pomocí následujícího kódu:

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();
        }
    }
}

Kód zkontroluje, jestli v databázi nejsou žádní studenti. Pokud nejsou žádní studenti, přidá do databáze testovací data. Vytvoří testovací data v polích místo List<T> kolekcí pro optimalizaci výkonu.

  • V Program.cs, odebrat // z DbInitializer.Initialize řádku:

      context.Database.EnsureCreated();
      DbInitializer.Initialize(context);
    
  • Pokud je aplikace spuštěná, zastavte ji a v konzole Správce balíčků (PMC) spusťte následující příkaz:

    Drop-Database -Confirm
    
    
  • Odpovězte na Y odstranění databáze.

  • Restartujte aplikaci.
  • Výběrem stránky Studenti zobrazíte počáteční data.

Zobrazení databáze

  • V nabídce Zobrazit v sadě Visual Studio otevřete SQL Server Průzkumník objektů (SSOX).
  • V nástroji SSOX vyberte (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Název databáze se vygeneruje z názvu kontextu, který jste zadali dříve, a navíc pomlčku a identifikátor GUID.
  • Rozbalte uzel Tabulky.
  • Klikněte pravým tlačítkem myši na tabulku Student a kliknutím na Zobrazit data zobrazte sloupce vytvořené a řádky vložené do tabulky.
  • Klikněte pravým tlačítkem myši na tabulku Student a kliknutím na Zobrazit kód zobrazte, jak se Student model mapuje na Student schéma tabulky.

Asynchronní kód

Asynchronní programování je výchozí režim pro ASP.NET Core a EF Core.

Webový server má k dispozici omezený počet vláken a v situacích s vysokým zatížením se můžou používat všechna dostupná vlákna. V takovém případě nemůže server zpracovat nové požadavky, dokud se vlákna nevysadí. V synchronním kódu může být mnoho vláken svázané, zatímco nefungují, protože čekají na dokončení vstupně-výstupních operací. Když proces čeká na dokončení vstupně-výstupních operací, v asynchronním kódu se jeho vlákno uvolní, aby server používal ke zpracování dalších požadavků. V důsledku toho asynchronní kód umožňuje efektivnější použití serverových prostředků a server dokáže zpracovat větší provoz bez zpoždění.

Asynchronní kód zavádí v době běhu malé režijní náklady. U situací s nízkým provozem je dosažení výkonu zanedbatelné, zatímco u vysokých dopravních situací je potenciální zlepšení výkonu podstatné.

V následujícím kódu asynchronní klíčové slovo, Task návratová hodnota, await klíčové slovo a ToListAsync metoda vytvoří kód asynchronně.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Klíčové async slovo říká kompilátoru, aby:
    • Vygenerujte zpětná volání pro části těla metody.
    • Vytvořte vrácený objekt Task .
  • Návratový Task typ představuje probíhající práci.
  • Klíčové await slovo způsobí, že kompilátor rozdělí metodu do dvou částí. První část končí operací, která se spouští asynchronně. Druhá část se vloží do metody zpětného volání, která se volá při dokončení operace.
  • ToListAsync je asynchronní verze ToList metody rozšíření.

Při psaní asynchronního kódu, který používá EF Core:

  • Asynchronně se spustí pouze příkazy, které způsobují odeslání dotazů nebo příkazů do databáze. To zahrnuje ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsynca SaveChangesAsync. Neobsahuje příkazy, které jen mění , IQueryablenapříklad var students = context.Students.Where(s => s.LastName == "Davolio").
  • Kontext EF Core není bezpečný pro vlákno: Nepokoušejte se paralelně provádět více operací.
  • Pokud chcete využít výhod výkonu asynchronního kódu, ověřte, že balíčky knihoven (například pro stránkování) používají asynchronní, pokud volají EF Core metody, které odesílají dotazy do databáze.

Další informace o asynchronním programování v .NET naleznete v tématu Přehled asynchronního a asynchronního programování pomocí asynchronního a await.

Důležité informace o výkonu

Obecně platí, že webová stránka by neměla načítat libovolný počet řádků. Dotaz by měl používat stránkování nebo omezený přístup. Předchozí dotaz může například použít Take k omezení vrácených řádků:

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

Výčet velké tabulky v zobrazení by mohl vrátit částečně sestavenou odpověď HTTP 200, pokud dojde k výčtu výjimky databáze.

MaxModelBindingCollectionSize výchozí hodnota je 1024. Následující sady MaxModelBindingCollectionSizekódu:

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();
}

Informace o nastavení konfigurace, jako je MyMaxModelBindingCollectionSize.

Stránkování se zabývá později v tomto kurzu.

Další informace najdete v tématu Důležité informace o výkonu (EF).

Protokolování SQL entity Framework Core

Konfiguraci protokolování obvykle zajišťuje oddíl Logging souborů appsettings.{Environment}.json. Pokud chcete protokolovat příkazy SQL, přidejte "Microsoft.EntityFrameworkCore.Database.Command": "Information" do appsettings.Development.json souboru:

{
  "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": "*"
}

U předchozích JSpříkazů ON se příkazy SQL zobrazí na příkazovém řádku a v okně výstupu sady Visual Studio.

Další informace najdete v tématu Protokolování v .NET Core a ASP.NET Core a tento problém na GitHubu.

Další kroky

Použití SQLite pro vývoj, SQL Server pro produkční prostředí

Toto je první v řadě kurzů, které ukazují, jak používat Entity Framework (EF) Core v aplikaci ASP.NET Core Razor Pages . Kurzy vytvářejí web pro fiktivní univerzitu Contoso. Web obsahuje funkce, jako je přijetí studentů, vytvoření kurzu a zadání instruktora. Tento kurz používá první přístup kódu. Informace o sledování tohoto kurzu s využitím prvního přístupu k databázi najdete v tomto problému na GitHubu.

Stáhněte nebo zobrazte dokončenou aplikaci.Pokyny ke stažení

Požadavky

Databázové stroje

Pokyny pro Visual Studio používají SQL Server LocalDB, verzi SQL Serveru Express, která běží jenom ve Windows.

Pokyny pro Visual Studio Code používají SQLite, databázový stroj pro různé platformy.

Pokud se rozhodnete používat SQLite, stáhněte a nainstalujte nástroj třetí strany pro správu a zobrazení databáze SQLite, například prohlížeč databáze pro SQLite.

Řešení potíží

Pokud narazíte na problém, který nemůžete vyřešit, porovnejte kód s dokončeným projektem. Dobrý způsob, jak získat pomoc, je odesláním otázky na StackOverflow.com pomocí značky ASP.NET Core nebo značkyEF Core.

Ukázková aplikace

Aplikace vytvořená v těchto kurzech je základní web pro vysokoškoláky. Uživatelé můžou zobrazit a aktualizovat informace o studentech, kurzech a instruktorech. Tady je několik obrazovek vytvořených v kurzu.

Students Index page

Students Edit page

Styl uživatelského rozhraní tohoto webu je založený na předdefinovaných šablonách projektů. Tento kurz se zaměřuje na to, jak používat EF Core, nikoli jak přizpůsobit uživatelské rozhraní.

Pokud chcete získat zdrojový kód dokončeného projektu, postupujte podle odkazu v horní části stránky. Složka cu30 obsahuje kód pro verzi kurzu ASP.NET Core 3.0. Soubory, které odrážejí stav kódu pro kurzy 1-7, najdete ve složce cu30snapshots .

Spuštění aplikace po stažení dokončeného projektu:

  • Sestavte projekt.

  • V konzole Správce balíčků (PMC) spusťte následující příkaz:

    Update-Database
    
  • Spuštěním projektu zasadíte databázi.

Vytvoření projektu webové aplikace

  • V nabídce Soubor sady Visual Studio vyberte Nový>projekt.
  • Vyberte ASP.NET Základní webová aplikace.
  • Pojmenujte projekt ContosoUniversity. Je důležité použít tento přesný název včetně velkých písmen, aby se obory názvů při kopírování a vkládání kódu shodovaly.
  • V rozevíracích sadě vyberte .NET Core a ASP.NET Core 3.0 a pak vyberte Webová aplikace.

Nastavení stylu webu

Nastavení záhlaví, zápatí webu a nabídky aktualizací Pages/Shared/_Layout.cshtml:

  • Změňte každý výskyt "ContosoUniversity" na "Contoso University". Existují tři výskyty.

  • Home Odstraňte položky a Privacy položky nabídky a přidejte položky pro informace, studenty, kurzy, instruktory a oddělení.

Změny jsou zvýrazněné.

<!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>

Nahraďte Pages/Index.cshtmlobsah souboru následujícím kódem, který nahradí text o ASP.NET Core textem o této aplikaci:

@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>

Spuštěním aplikace ověřte, že se zobrazí domovská stránka.

Datový model

Následující části vytvoří datový model:

Course-Enrollment-Student data model diagram

Student se může zaregistrovat do libovolného počtu kurzů a kurz může mít v něm zaregistrovaný libovolný počet studentů.

Entita Student

Student entity diagram

  • Ve složce projektu vytvořte složku Models .

  • Vytvořte Models/Student.cs pomocí následujícího kódu:

    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; }
        }
    }
    

Vlastnost ID se stane sloupcem primárního klíče v tabulce databáze, která odpovídá této třídě. Ve výchozím nastavení interpretuje vlastnost, EF Core která je pojmenovaná ID nebo classnameID jako primární klíč. Proto je alternativou automaticky rozpoznaný název primárního Student klíče StudentIDtřídy . Další informace najdete v tématu EF Core – Klíče.

Vlastnost Enrollments je navigační vlastnost. Vlastnosti navigace obsahují další entity, které souvisejí s touto entitou. V tomto případě Enrollments vlastnost Student entity obsahuje všechny Enrollment entity, které se vztahují k tomuto studentu. Pokud má například řádek Student v databázi dva související řádky registrace, Enrollments navigační vlastnost obsahuje tyto dvě entity registrace.

V databázi se řádek Registrace vztahuje k řádku Student, pokud jeho sloupec StudentID obsahuje hodnotu ID studenta. Předpokládejme například, že řádek Student má ID=1. Související řádky registrace budou mít ID studenta = 1. ID studenta je cizí klíč v tabulce Registrace.

Vlastnost je definována Enrollments , protože ICollection<Enrollment> může existovat více souvisejících entit registrace. Můžete použít jiné typy kolekcí, například List<Enrollment> nebo HashSet<Enrollment>. Při ICollection<Enrollment> použití EF Core vytvoří kolekci HashSet<Enrollment> ve výchozím nastavení.

Entita Registrace

Enrollment entity diagram

Vytvořte Models/Enrollment.cs pomocí následujícího kódu:

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; }
    }
}

Vlastnost EnrollmentID je primární klíč; tato entita používá classnameID vzor místo ID sebe sama. Pro produkční datový model zvolte jeden vzor a používejte ho konzistentně. V tomto kurzu se obě používají k ilustraci toho, že obě fungují. Použití ID bez classname usnadnění implementace některých druhů změn datového modelu.

Vlastnost Grade je .enum Otazník za Grade deklaraci typu označuje, že Grade vlastnost je nullable. Známka, která má hodnotu null, se liší od nulové známky – hodnota null znamená, že známka není známa nebo ještě nebyla přiřazena.

Vlastnost StudentID je cizí klíč a odpovídající navigační vlastnost je Student. Entita Enrollment je přidružená k jedné Student entitě, takže vlastnost obsahuje jednu Student entitu.

Vlastnost CourseID je cizí klíč a odpovídající navigační vlastnost je Course. Entita Enrollment je přidružená k jedné Course entitě.

EF Core interpretuje vlastnost jako cizí klíč, pokud je pojmenovaná <navigation property name><primary key property name>. Je to napříkladStudentID cizí klíč pro Student navigační vlastnost, protože Student primární klíč entity je ID. Vlastnosti cizího klíče lze také pojmenovat <primary key property name>. Například vzhledem k tomu, CourseID že Course primární klíč entity je CourseID.

Entita Course

Course entity diagram

Vytvořte Models/Course.cs pomocí následujícího kódu:

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; }
    }
}

Vlastnost Enrollments je navigační vlastnost. Entita Course může souviset s libovolným počtem Enrollment entit.

Atribut DatabaseGenerated umožňuje aplikaci místo vygenerování databáze zadat primární klíč.

Sestavte projekt, abyste ověřili, že nedošlo k žádným chybám kompilátoru.

Vygenerované stránky studentů

V této části použijete nástroj pro generování uživatelského rozhraní ASP.NET Core:

  • Třída EF Corekontextu . Kontext je hlavní třída, která koordinuje funkce Entity Framework pro daný datový model. Odvozuje z Microsoft.EntityFrameworkCore.DbContext třídy.
  • Razor stránky, které zpracovávají operace vytvoření, čtení, aktualizace a odstranění (CRUD) pro entitu Student .
  • Ve složce Pages vytvořte složku Students.
  • V Průzkumník řešení klikněte pravým tlačítkem na složku Pages/Students a vyberte Přidat>novou vygenerovanou položku.
  • V dialogovém okně Přidat generování uživatelského rozhraní vyberte Razor Stránky pomocí entity Framework (CRUD)>ADD.
  • V dialogovém okně Přidat Razor stránky pomocí entity Framework (CRUD):
    • V rozevíracím seznamu Třída modelu vyberte Student (ContosoUniversity.Models).
    • V řádku třídy kontextu dat vyberte znaménko + (plus).
    • Změňte název kontextu dat z ContosoUniversity.Models.ContosoUniversityContext na ContosoUniversity.Data.SchoolContext.
    • Vyberte Přidat.

Automaticky se nainstalují následující balíčky:

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

Pokud máte potíže s předchozím krokem, sestavte projekt a zopakujte krok generování.

Proces generování uživatelského rozhraní:

  • Vytvoří Razor stránky ve složce Pages/Students :
    • Create.cshtml a Create.cshtml.cs
    • Delete.cshtml a Delete.cshtml.cs
    • Details.cshtml a Details.cshtml.cs
    • Edit.cshtml a Edit.cshtml.cs
    • Index.cshtml a Index.cshtml.cs
  • Vytvoří Data/SchoolContext.cs.
  • Přidá kontext do injektáže závislostí v Startup.cssouboru .
  • Přidá databázi připojovací řetězec do appsettings.json.

Připojovací řetězec databáze

Soubor appsettings.json určuje připojovací řetězec SQL Server LocalDB.

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

LocalDB je zjednodušená verze databázového stroje SQL Server Express a je určená pro vývoj aplikací, nikoli pro produkční použití. Ve výchozím nastavení vytvoří LocalDB soubory .mdf v C:/Users/<user> adresáři.

Aktualizace třídy kontextu databáze

Hlavní třída, která koordinuje EF Core funkce pro daný datový model, je třída kontextu databáze. Kontext je odvozen z Microsoft.EntityFrameworkCore.DbContext. Kontext určuje, které entity jsou součástí datového modelu. V tomto projektu má třída název SchoolContext.

Aktualizujte Data/SchoolContext.cs následujícím kódem:

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");
        }
    }
}

Zvýrazněný kód vytvoří DbSet<TEntity> vlastnost pro každou sadu entit. V EF Core terminologii:

  • Sada entit obvykle odpovídá databázové tabulce.
  • Entita odpovídá řádku v tabulce.

Vzhledem k tomu, že sada entit obsahuje více entit, vlastnosti DBSet by měly být názvy množného čísla. Vzhledem k tomu, že nástroj pro generování uživatelského rozhraní vytvořilStudent sadu DBSet, tento krok ho změní na množné číslo Students.

Pokud chcete, aby Razor kód Pages odpovídal novému názvu dbSet, proveďte globální změnu v celém projektu _context.Student na _context.Students. Existuje 8 výskytů.

Sestavte projekt, abyste ověřili, že nedošlo k žádným chybám kompilátoru.

Startup.cs

ASP.NET Core se sestavuje pomocí injektáže závislostí. Služby (například EF Core kontext databáze) se během spouštění aplikace registrují pomocí injektáže závislostí. Komponenty, které vyžadují tyto služby (například Razor stránky), jsou tyto služby poskytovány prostřednictvím parametrů konstruktoru. Kód konstruktoru, který získá instanci kontextu databáze, se zobrazí později v kurzu.

Nástroj pro generování uživatelského rozhraní automaticky zaregistroval třídu kontextu s kontejnerem injektáže závislostí.

  • V ConfigureServices, zvýrazněné čáry byly přidány scaffolder:

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

Název připojovací řetězec se předává kontextu voláním metody na objektuDbContextOptions. V případě místního vývoje načte konfigurační systém ASP.NET Core připojovací řetězec ze appsettings.json souboru.

Vytvoření databáze

Aktualizujte Program.cs databázi, pokud neexistuje:

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>();
                });
    }
}

Metoda EnsureCreated neprobíná žádnou akci, pokud existuje databáze pro kontext. Pokud žádná databáze neexistuje, vytvoří databázi a schéma. EnsureCreated umožňuje následující pracovní postup pro zpracování změn datového modelu:

  • Odstraňte databázi. Všechna existující data se ztratí.
  • Změňte datový model. Můžete například přidat EmailAddress pole.
  • Spustit aplikaci.
  • EnsureCreated vytvoří databázi s novým schématem.

Tento pracovní postup funguje dobře v rané fázi vývoje, pokud se schéma rychle vyvíjí, pokud nepotřebujete zachovat data. Situace se liší, když je potřeba zachovat data zadaná do databáze. V takovém případě použijte migrace.

Později v sérii kurzů odstraníte databázi, kterou jste vytvořili EnsureCreated , a místo toho použijete migrace. Databázi vytvořenou pomocí EnsureCreated migrací nejde aktualizovat.

Otestování aplikace

  • Spustit aplikaci.
  • Vyberte odkaz Studenti a pak vytvořte nový.
  • Otestujte odkazy Upravit, Podrobnosti a Odstranit.

Počáteční hodnota databáze

Metoda EnsureCreated vytvoří prázdnou databázi. Tato část přidá kód, který naplní databázi testovacími daty.

Vytvořte Data/DbInitializer.cs pomocí následujícího kódu:

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();
        }
    }
}

Kód zkontroluje, jestli v databázi nejsou žádní studenti. Pokud nejsou žádní studenti, přidá do databáze testovací data. Vytvoří testovací data v polích místo List<T> kolekcí pro optimalizaci výkonu.

  • V Program.csčásti , nahraďte EnsureCreated hovor voláním DbInitializer.Initialize :

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

Pokud je aplikace spuštěná, zastavte ji a v konzole Správce balíčků (PMC) spusťte následující příkaz:

Drop-Database
  • Restartujte aplikaci.

  • Výběrem stránky Studenti zobrazíte počáteční data.

Zobrazení databáze

  • V nabídce Zobrazit v sadě Visual Studio otevřete SQL Server Průzkumník objektů (SSOX).
  • V nástroji SSOX vyberte (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Název databáze se vygeneruje z názvu kontextu, který jste zadali dříve a pomlčku a identifikátor GUID.
  • Rozbalte uzel Tabulky.
  • Klikněte pravým tlačítkem myši na tabulku Student a kliknutím na Zobrazit data zobrazte sloupce vytvořené a řádky vložené do tabulky.
  • Klikněte pravým tlačítkem myši na tabulku Student a kliknutím na Zobrazit kód zobrazte, jak se Student model mapuje na Student schéma tabulky.

Asynchronní kód

Asynchronní programování je výchozí režim pro ASP.NET Core a EF Core.

Webový server má k dispozici omezený počet vláken a v situacích s vysokým zatížením se můžou používat všechna dostupná vlákna. V takovém případě nemůže server zpracovat nové požadavky, dokud se vlákna nevysadí. V synchronním kódu může být mnoho vláken svázané, zatímco ve skutečnosti neprovádí žádnou práci, protože čekají na dokončení vstupně-výstupních operací. Když proces čeká na dokončení vstupně-výstupních operací, v asynchronním kódu se jeho vlákno uvolní, aby server používal ke zpracování dalších požadavků. V důsledku toho asynchronní kód umožňuje efektivnější použití serverových prostředků a server dokáže zpracovat větší provoz bez zpoždění.

Asynchronní kód zavádí v době běhu malé režijní náklady. U situací s nízkým provozem je dosažení výkonu zanedbatelné, zatímco u vysokých dopravních situací je potenciální zlepšení výkonu podstatné.

V následujícím kódu asynchronní klíčové slovo, Task<T> návratová hodnota, await klíčové slovo a ToListAsync metoda vytvoří kód asynchronně.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Klíčové async slovo říká kompilátoru, aby:
    • Vygenerujte zpětná volání pro části těla metody.
    • Vytvořte vrácený objekt Task .
  • Návratový Task<T> typ představuje probíhající práci.
  • Klíčové await slovo způsobí, že kompilátor rozdělí metodu do dvou částí. První část končí operací, která se spouští asynchronně. Druhá část se vloží do metody zpětného volání, která se volá při dokončení operace.
  • ToListAsync je asynchronní verze ToList metody rozšíření.

Při psaní asynchronního kódu, který používá EF Core:

  • Asynchronně se spustí pouze příkazy, které způsobují odeslání dotazů nebo příkazů do databáze. To zahrnuje ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsynca SaveChangesAsync. Neobsahuje příkazy, které jen mění , IQueryablenapříklad var students = context.Students.Where(s => s.LastName == "Davolio").
  • Kontext EF Core není bezpečný pro vlákno: Nepokoušejte se paralelně provádět více operací.
  • Pokud chcete využít výhod výkonu asynchronního kódu, ověřte, že balíčky knihoven (například pro stránkování) používají asynchronní, pokud volají EF Core metody, které odesílají dotazy do databáze.

Další informace o asynchronním programování v .NET naleznete v tématu Přehled asynchronního a asynchronního programování pomocí asynchronního a await.

Další kroky