RazorStrá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í contososkou univerzitu. Web zahrnuje funkce, jako je například přijetí studentů, vytváření kurzů a zadání instruktora. Tento kurz používá první přístup kódu. Informace o provedení tohoto kurzu pomocí 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 Visual Studio používají SQL Server LocalDB, verzi SQL Server Express, která běží jenom na 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ým způsobem, jak získat pomoc, je odesláním otázky do StackOverflow.com pomocí značky ASP.NET Core nebo značky EF Core.

Ukázková aplikace

Aplikace integrovaná 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 s ASP.NET Core, nikoli jak přizpůsobit uživatelské rozhraní.

Volitelné: Sestavení ukázky ke stažení

Tento krok je volitelný. 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 Správce balíčků Console (PMC) spusťte následující příkaz:

    Update-Database
    

Spusťte projekt tak, aby se databáze osílala.

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 ContosoUniversitynázev Project. Je důležité pojmenovat projekt ContosoUniversity, včetně porovnávání velkých písmen, takže se obory názvů budou shodovat při kopírování a vkládání ukázkového kódu.

  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 souboru následující kód Pages/Shared/_Layout.cshtml :

<!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" do "Contoso University". Existují tři výskyty.
  • Položky Home nabídky a Privacy nabídky se odstraní.
  • Položky jsou přidány pro informace, studenty, kurzy, instruktory a oddělení.

V Pages/Index.cshtmlsouboru nahraďte obsah 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.

Spusťte aplikaci a 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 v libovolném počtu kurzů a kurz může mít libovolný počet studentů zaregistrovaných v něm.

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 primárním klíčem sloupce databázové tabulky, která odpovídá této třídě. Ef Core ve výchozím nastavení interpretuje vlastnost, která je pojmenovaná ID nebo classnameID jako primární klíč. Takže alternativní automaticky rozpoznaný název primárního Student klíče třídy je StudentID. 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é souvisejí s tímto studentem. 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 obsahovat StudentID = 1. StudentID je cizí klíč v tabulce Registrace.

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

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 je primárním klíčem. Tato EnrollmentID entita místo sebe používá classnameID vzor ID . V případě produkčního datového modelu si mnoho vývojářů zvolí jeden vzor a bude ho používat konzistentně. V tomto kurzu se obě používají k ilustraci toho, že oba fungují. Použití ID bez classname usnadňuje implementaci 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 null. 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 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 Kurzu

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 Enrollment počtem entit.

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

Sestavení aplikace Kompilátor vygeneruje několik upozornění na způsob null zpracování hodnot. Podívejte se na tento GitHub problém, typy odkazů s možnou hodnotou Null a Kurz: Pokud chcete získat další informace, vyjádřete záměr návrhu jasněji s odkazovými typy s možnou hodnotou null a nenulovou hodnotou.

Chcete-li odstranit upozornění z typů odkazů 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, proto modely použité v generování uživatelského rozhraní ani nemohou.

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

Generování stránek studentů

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

  • Třída EF Core DbContext . Kontext je hlavní třída, která koordinuje funkce Entity Framework pro daný datový model. Odvozuje se od Microsoft.EntityFrameworkCore.DbContext třídy.
  • Razor stránky, které zpracovávají operace vytvoření, čtení, aktualizace a odstranění (CRUD) pro danou 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 AddNew>Scaffolded Item.
  • 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 spíše než 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.cs.
  • Přidá připojovací řetězec databáze do appsettings.json.

Připojovací řetězec databáze

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

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í. LocalDB ve výchozím nastavení vytvoří v C:/Users/<user> adresáři soubory .mdf.

Aktualizace třídy kontextu databáze

Hlavní třída, která koordinuje funkce EF Core pro daný datový model, je třída kontextu databáze. Kontext je odvozen od 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. na: _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:

  • DbSet<TEntity> Vytvoří vlastnost pro každou sadu entit. V terminologii EF Core:
    • Sada entit obvykle odpovídá databázové tabulce.
    • Entita odpovídá řádku v tabulce.
  • Volání OnModelCreating. OnModelCreating:
    • Volá se, když SchoolContext byl inicializován, ale před uzamčením modelu a použitým k inicializaci kontextu.
    • Vyžaduje se, 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 je sestaven pomocí injektáže závislostí. Služby, jako je například injektáž SchoolContext závislostí, se registrují během spouštění aplikace. Tyto služby jsou poskytovány prostřednictvím parametrů konstruktoru, které vyžadují tyto služby, například Razor Stránky. 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ího řetězce se předá kontextu voláním metody objektu DbContextOptions . V případě místního vývoje ASP.NET Core konfigurační systém přečte připojovací řetězec z appsettings.json souboru nebo appsettings.Development.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:

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 microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet.

Do konzoly 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 Core middleware 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 povolí 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.
  • Spusťte 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í a EnsureCreated použije se migrace. Databázi vytvořenou EnsureCreated pomocí migrací nejde aktualizovat.

Otestování aplikace

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

Počáteční 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
    
    
  • Y Odpovězte na 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 Visual Studio otevřete SQL Server Průzkumník objektů (SSOX).
  • V SSOX vyberte (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Název databáze se vygeneruje z názvu kontextu, který jste zadali dříve, plus 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ím režimem pro ASP.NET Core a EF Core.

Webový server má 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. Když k tomu dojde, server nemůže zpracovat nové požadavky, dokud se vlákna uvolní. Při synchronním kódu může být mnoho vláken svázané, když nepracují, protože čekají na dokončení vstupně-výstupních operací. Když proces čeká na dokončení vstupně-výstupních operací, uvolní se u asynchronního kódu, aby server používal ke zpracování jiných požadavků. V důsledku toho asynchronní kód umožňuje efektivnější použití prostředků serveru a server může zpracovávat více provozu bez zpoždění.

Asynchronní kód zavádí v době běhu malé režijní náklady. V případě nízkých dopravních situací 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 provede asynchronní klíčové slovo, Task návratovou hodnotu, await klíčové slovo a ToListAsync metodu, aby se kód spustil asynchronně.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Klíčové async slovo kompilátoru říká:
    • Vygenerujte zpětné volání pro části těla metody.
    • Vytvořte vrácený objekt Úkolu .
  • 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á po dokončení operace.
  • ToListAsync je asynchronní verze ToList metody rozšíření.

Při psaní asynchronního kódu, který používá EF Core, je potřeba mít na paměti některé věci:

  • Asynchronně se spustí pouze příkazy, které způsobují odeslání dotazů nebo příkazů do databáze. To zahrnuje ToListAsync, , FirstOrDefaultAsyncSingleOrDefaultAsynca SaveChangesAsync. Neobsahuje příkazy, které jenom mění IQueryable, napří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í metody EF Core, které odesílají dotazy do databáze.

Další informace o asynchronním programování v .NET najdete v tématu Přehled asynchronního a asynchronního programování s asynchronním a awaitm.

Otázky 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. Například předchozí dotaz může 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 věnuje 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í contososkou univerzitu. 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 provedení tohoto kurzu pomocí 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 Visual Studio používají SQL Server LocalDB, verzi SQL Server Express, která běží jenom na 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ým způsobem, jak získat pomoc, je odesláním otázky do StackOverflow.com pomocí značky ASP.NET Core nebo značky EF Core.

Ukázková aplikace

Aplikace integrovaná 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 s ASP.NET Core, nikoli jak přizpůsobit uživatelské rozhraní.

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

Tento krok je volitelný. 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

Spusťte projekt tak, aby se databáze zasadila.

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 Core WebApplicationNext>.
  3. V dialogovém okně Konfigurovat nový projekt zadejte ContosoUniversitynázev Project. Je důležité použít tento přesný název včetně velká písmena, takže každý z nich namespace odpovídá při zkopírování kódu.
  4. Vyberte Vytvořit.
  5. V dialogovém okně Vytvořit novou ASP.NET Core webové aplikace vyberte:
    1. .NET Core a ASP.NET Core 5.0 v rozevíracích sadě.
    2. ASP.NET Core webovou aplikaci.
    3. VytvořitNew ASP.NET Core Project dialog

Nastavení stylu webu

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

<!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" do "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 informace, studenty, kurzy, instruktory a oddělení.

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.

Spusťte aplikaci a 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 v něm může mít 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 primárním klíčem sloupce databázové tabulky, která odpovídá této třídě. EF Core ve výchozím nastavení interpretuje vlastnost, která je pojmenovaná ID nebo classnameID jako primární klíč. Takže alternativní automaticky rozpoznaný název primárního Student klíče třídy je StudentID. 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é souvisejí s daným studentem. 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. StudentID 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. Lze použít jiné typy kolekcí, například List<Enrollment>HashSet<Enrollment>. Když ICollection<Enrollment> se použije, EF Core ve výchozím nastavení vytvoří HashSet<Enrollment> kolekci.

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ím klíčem; tato entita classnameID místo sebe používá vzor ID . V případě produkčního datového modelu si mnoho vývojářů vybírá jeden vzor a používá ho konzistentně. V tomto kurzu se oba používají k ilustraci, že obě fungují. Použití ID bez classname toho usnadňuje implementaci některých typů změn datového modelu.

Vlastnost Grade je .enum Otazník po Grade deklaraci typu označuje, že Grade vlastnost je null. Známka, která má hodnotu null, se liší od nulové úrovně – 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 například cizí klíč pro Student navigační vlastnost,StudentID protože Student primární klíč entity je ID. Vlastnosti cizího klíče mohou být také pojmenovány <primary key property name>. Například vzhledem k tomu, CourseID že Course primární klíč entity je CourseID.

Entita kurzu

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 Enrollment počtem entit.

Atribut DatabaseGenerated umožňuje aplikaci určit primární klíč místo toho, aby ji databáze vygenerovala.

Sestavte projekt, abyste ověřili, že neexistují žádné chyby kompilátoru.

Stránky studentů s generováním uživatelského rozhraní

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

  • Třída EF Core DbContext . Kontext je hlavní třída, která koordinuje funkce Entity Framework pro daný datový model. Pochází 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 myši na složku Stránky/Studenti 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 místo SchoolContextContosoUniversityContext. 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 GitHub problém.

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 opakujte 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 k injektáži závislostí v Startup.cssouboru .
  • Přidá připojovací řetězec databáze do appsettings.jsonsouboru .

Připojovací řetězec databáze

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

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 produkční použití. LocalDB ve výchozím nastavení vytvoří soubory .mdf v C:/Users/<user> adresáři.

Aktualizace třídy kontextu databáze

Hlavní třída, která koordinuje funkce EF Core pro daný datový model, je třída kontextu databáze. Kontext je odvozen od 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 názvu, proveďte globální DBSet změnu z:_context.Student. do: _context.Students.

Existuje 8 výskytů.

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

Zvýrazněný kód:

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

Sestavte projekt, abyste ověřili, že neexistují žádné chyby kompilátoru.

Startup.cs

ASP.NET Core je sestaven pomocí injektáže závislostí. Služby, jako SchoolContext jsou 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 těmito službami 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ího řetězce se předá kontextu voláním metody objektu DbContextOptions . Pro místní vývoj ASP.NET Core konfigurační systém načte 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 microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet.

Do konzoly 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 Core middleware 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 povolí 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.
  • Spusťte 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í a EnsureCreated použije se migrace. Databázi vytvořenou EnsureCreated pomocí migrací nejde aktualizovat.

Otestování aplikace

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

Počáteční 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
    
    
  • Y Odpovězte na 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 Visual Studio otevřete SQL Server Průzkumník objektů (SSOX).
  • V SSOX vyberte (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Název databáze se vygeneruje z názvu kontextu, který jste zadali dříve, plus 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ím režimem pro ASP.NET Core a EF Core.

Webový server má 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. Když k tomu dojde, server nemůže zpracovat nové požadavky, dokud se vlákna uvolní. Při synchronním kódu může být mnoho vláken svázané, když nepracují, protože čekají na dokončení vstupně-výstupních operací. Když proces čeká na dokončení vstupně-výstupních operací, uvolní se u asynchronního kódu, aby server používal ke zpracování jiných požadavků. V důsledku toho asynchronní kód umožňuje efektivnější použití prostředků serveru a server může zpracovávat více provozu bez zpoždění.

Asynchronní kód zavádí v době běhu malé režijní náklady. V případě nízkých dopravních situací 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 provede asynchronní klíčové slovo, Task návratovou hodnotu, await klíčové slovo a ToListAsync metodu, aby se kód spustil asynchronně.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Klíčové async slovo kompilátoru říká:
    • Vygenerujte zpětné volání pro části těla metody.
    • Vytvořte vrácený objekt Úkolu .
  • 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á po dokončení operace.
  • ToListAsync je asynchronní verze ToList metody rozšíření.

Při psaní asynchronního kódu, který používá EF Core, je potřeba mít na paměti některé věci:

  • Asynchronně se spustí pouze příkazy, které způsobují odeslání dotazů nebo příkazů do databáze. To zahrnuje ToListAsync, , FirstOrDefaultAsyncSingleOrDefaultAsynca SaveChangesAsync. Neobsahuje příkazy, které jenom mění IQueryable, napří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í metody EF Core, které odesílají dotazy do databáze.

Další informace o asynchronním programování v .NET najdete v tématu Přehled asynchronního a asynchronního programování s asynchronním a awaitm.

Otázky 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. Například předchozí dotaz může 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 věnuje později v tomto kurzu.

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

protokolování entity Framework Core SQL

Konfigurace protokolování se běžně poskytuje v Logging části appsettings.{Environment}.json souborů. Pokud chcete protokolovat SQL příkazy, přidejte "Microsoft.EntityFrameworkCore.Database.Command": "Information" je 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": "*"
}

V předchozím kódu JSON se příkazy SQL zobrazí na příkazovém řádku a v okně výstupu Visual Studio.

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

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í contososkou univerzitu. 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 provedení tohoto kurzu pomocí 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 Visual Studio používají SQL Server LocalDB, verzi SQL Server Express, která běží jenom na Windows.

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

Pokud se rozhodnete použít SQLite, stáhněte a nainstalujte nástroj třetí strany pro správu a prohlížení databáze SQLite, jako je například prohlížeč databáze DB 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ým způsobem, jak získat pomoc, je odesláním otázky do StackOverflow.com pomocí značky ASP.NET Core nebo značky EF Core.

Ukázková aplikace

Aplikace integrovaná 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 pro dokončený projekt, postupujte podle odkazu v horní části stránky. Složka cu30 obsahuje kód pro ASP.NET Core 3.0 verze kurzu. 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
    
  • Spusťte projekt tak, aby se databáze zasadila.

Vytvoření projektu webové aplikace

  • V nabídce Visual Studio Soubor vyberte Nový>Project.
  • Vyberte ASP.NET Core webovou aplikaci.
  • Pojmenujte projekt ContosoUniversity. Je důležité použít tento přesný název včetně velkých písmen, takže obory názvů se shodují, když se kód zkopíruje a vloží.
  • V rozevíracích sadě vyberte .NET Core a ASP.NET Core 3.0 a pak vyberte Web Application.

Nastavení stylu webu

Nastavení záhlaví webu, zápatí 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>

Spusťte aplikaci a 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 v něm může mít 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 primárním klíčem sloupce databázové tabulky, která odpovídá této třídě. EF Core ve výchozím nastavení interpretuje vlastnost, která je pojmenovaná ID nebo classnameID jako primární klíč. Takže alternativní automaticky rozpoznaný název primárního Student klíče třídy je StudentID. 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é souvisejí s daným studentem. 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 souvisí řádek Registrace s řádkem Student, pokud 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> .HashSet<Enrollment> Když ICollection<Enrollment> se použije, EF Core ve výchozím nastavení vytvoří HashSet<Enrollment> kolekci.

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ím klíčem; tato entita classnameID místo sebe používá vzor ID . V případě produkčního datového modelu zvolte jeden vzor a používejte ho konzistentně. V tomto kurzu se oba používají k ilustraci, že obě fungují. Použití ID bez classname toho usnadňuje implementaci některých typů změn datového modelu.

Vlastnost Grade je .enum Otazník po Grade deklaraci typu označuje, že Grade vlastnost je null. Známka, která má hodnotu null, se liší od nulové úrovně – 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 například cizí klíč pro Student navigační vlastnost,StudentID protože Student primární klíč entity je ID. Vlastnosti cizího klíče mohou být také pojmenovány <primary key property name>. Například vzhledem k tomu, CourseID že Course primární klíč entity je CourseID.

Entita kurzu

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 Enrollment počtem entit.

Atribut DatabaseGenerated umožňuje aplikaci určit primární klíč místo toho, aby ji databáze vygenerovala.

Sestavte projekt, abyste ověřili, že neexistují žádné chyby kompilátoru.

Stránky studentů s generováním uživatelského rozhraní

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

  • Třída kontextu EF Core. Kontext je hlavní třída, která koordinuje funkce Entity Framework pro daný datový model. Pochází 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 Studenti.
  • V Průzkumník řešení klikněte pravým tlačítkem myši na složku Stránky/Studenti 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 zkuste znovu spustit 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 k injektáži závislostí v Startup.cssouboru .
  • Přidá připojovací řetězec databáze do appsettings.jsonsouboru .

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 produkční použití. LocalDB ve výchozím nastavení vytvoří soubory .mdf v C:/Users/<user> adresáři.

Aktualizace třídy kontextu databáze

Hlavní třída, která koordinuje funkce EF Core pro daný datový model, je třída kontextu databáze. Kontext je odvozen od 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 terminologii EF Core:

  • 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.

Chcete-li, aby Razor kód Stránky 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 neexistují žádné chyby kompilátoru.

Startup.cs

ASP.NET Core je sestaven pomocí injektáže závislostí. Služby (například kontext databáze EF Core) 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ího řetězce se předá kontextu voláním metody objektu DbContextOptions . Pro místní vývoj 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, aby se vytvořila, 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írá žádnou akci, pokud existuje databáze kontextu. 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. Přidejte například EmailAddress pole.
  • Spusťte aplikaci.
  • EnsureCreated vytvoří databázi s novým schématem.

Tento pracovní postup funguje dobře v rané fázi vývoje při rychlém vývoji schématu, 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 vytvořenou EnsureCreated a místo toho použijete migrace. Databázi vytvořenou pomocí EnsureCreated migrací nejde aktualizovat.

Otestování aplikace

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

Ed the database

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

  • Otevřete SQL Server Průzkumník objektů (SSOX) v nabídce Zobrazení v Visual Studio.
  • V 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 Student se 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. Když k tomu dojde, server nemůže zpracovat nové požadavky, dokud se vlákna nevysadí. Při 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í. Při asynchronním kódu, když proces čeká na dokončení vstupně-výstupních operací, jeho vlákno se 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í prostředků serveru a server dokáže zpracovat větší provoz bez zpoždění.

Asynchronní kód představuje malou režii za běhu. V případě nízkých dopravních situací je dosažení výkonu zanedbatelné, zatímco u situací s vysokým provozem je potenciální zlepšení výkonu podstatné.

V následujícím kódu asynchronní klíčové slovo , Task<T> vrátit hodnotu, await klíčové slovo a ToListAsync metodu, aby se kód spustil 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 úkolu .
  • Návratový Task<T> typ představuje probíhající práci.
  • await Klíčové slovo způsobí, že kompilátor rozdělí metodu na dvě části. První část končí operací, která se spouští asynchronně. Druhá část se vloží do metody zpětného volání, která se volá po dokončení operace.
  • ToListAsync je asynchronní verze ToList metody rozšíření.

Některé věci, které byste měli vědět 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, , SingleOrDefaultAsynca FirstOrDefaultAsyncSaveChangesAsync. Nezahrnuje příkazy, které pouze mění IQueryable, například var students = context.Students.Where(s => s.LastName == "Davolio").
  • Kontext EF Core není bezpečný: 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í metody EF Core, které odesílají dotazy do databáze.

Další informace o asynchronním programování v .NET najdete v tématu Přehled asynchronního a asynchronního programování s asynchronním a awaitm.

Další kroky