kurz: začínáme s EF Core ve webové aplikaci ASP.NET MVC

Dykstra a Rick Anderson

V tomto kurzu se ASP.NET Core MVC a Entity Framework Core s kontrolery a zobrazeními. Razor Pages je alternativní programovací model. Pro nový vývoj doporučujeme Pages Razor over MVC s kontrolery a zobrazeními. Podívejte se Razor na verzi Pages tohoto kurzu. Každý kurz se zabývá některými materiály, které druhý ne:

Tento kurz MVC obsahuje některé věci, které Razor kurz Pages ne:

  • Implementace dědičnosti v datovém modelu
  • Provádění nezpracovaných dotazů SQL
  • Zjednodušení kódu pomocí dynamického LINQ

Kurz Razor Pages obsahuje některé věci, které tento kurz ne:

  • Použití metody Select k načtení souvisejících dat
  • Osvědčené postupy pro EF.

ukázková webová aplikace společnosti Contoso University ukazuje, jak vytvořit webovou aplikaci ASP.NET Core MVC pomocí Entity Framework (EF) jádra a Visual Studio.

Ukázková aplikace je web pro fiktivní univerzitě společnosti Contoso. Zahrnuje funkce, jako je například využití studenta, vytváření kurzu a přiřazení instruktora. Toto je první v sérii kurzů, které vysvětlují, jak sestavit ukázkovou aplikaci Contoso University.

Požadavky

Databázové moduly

pokyny pro Visual Studio používají SQL Server LocalDB, což je verze SQL Server Express, která se spouští jenom na Windows.

Řešení problémů a odstraňování potíží

Pokud narazíte na problém, který nelze vyřešit, můžete řešení obecně najít porovnáním kódu s dokončeným projektem. Seznam běžných chyb a jejich řešení najdete v části věnované řešení potíží v posledním kurzu v řadě. pokud tam nenajdete, co potřebujete, můžete odeslat otázku do StackOverflow.com pro ASP.NET Core nebo EF Core.

Tip

Toto je série 10 kurzů, z nichž každá sestaví na tom, co se děje v předchozích kurzech. Zvažte uložení kopie projektu po každém úspěšném dokončení kurzu. Pak Pokud narazíte na problémy, můžete začít znovu z předchozího kurzu a nemusíte se vrátit na začátek celé řady.

Webová aplikace Contoso University

Aplikace sestavená v těchto kurzech je základním webem na univerzitě.

Uživatelé můžou zobrazit a aktualizovat informace o studentech, kurzech a instruktorech. Tady je několik obrazovek v aplikaci:

Stránka indexu studentů

Stránka pro úpravy studentů

Vytvoření webové aplikace

  1. spusťte Visual Studio a vyberte vytvořit nový projekt.
  2. v dialogovém okně vytvořit nový projekt vyberte možnost ASP.NET Core webová aplikace > další.
  3. v dialogovém okně konfigurace nového projektu zadejte ContosoUniversity pro Project název. Je důležité použít tento přesný název, včetně velkých a malých písmen, takže každá namespace Shoda při kopírování kódu.
  4. Vyberte Vytvořit.
  5. v dialogovém okně vytvořit novou webovou aplikaci ASP.NET Core vyberte:
    1. rozhraní .net Core a ASP.NET Core 5,0 v rozevíracích seznamech.
    2. ASP.NET Core webové aplikace (Model-View-Controller).
    3. Vytvořit  dialog nové Project ASP.NET Core

Nastavení stylu webu

V několika základních změnách se nastavuje nabídka webu, rozložení a Domovská stránka.

Otevřete views/Shared/_Layout. cshtml a proveďte následující změny:

  • Změňte všechny výskyty ContosoUniversity na Contoso University . Existují tři výskyty.
  • Přidejte položky nabídky pro, studenty, kurzy, instruktory a oddělení a odstraňte Privacy položku nabídky.

Předchozí změny jsou zvýrazněny v následujícím kódu:

<!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.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

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

V zobrazeních/ Home /index.cshtml nahraďte obsah souboru následujícím kódem:

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

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

Stisknutím kombinace kláves CTRL + F5 spusťte projekt nebo zvolte možnost ladění > spustit bez ladění z nabídky. Domovská stránka se zobrazí s kartami pro stránky vytvořené v tomto kurzu.

Domovská stránka společnosti Contoso University

balíčky NuGet EF Core

v tomto kurzu se používá SQL Server a balíček poskytovatele je Microsoft. EntityFrameworkCore. SqlServer.

balíček ef SQL Server a jeho závislosti Microsoft.EntityFrameworkCore a Microsoft.EntityFrameworkCore.Relational , poskytují běhovou podporu pro EF.

přidejte NuGet balíček Microsoft. AspNetCore. diagnostics. EntityFrameworkCore . v konzole Správce balíčků (PMC) zadejte následující příkazy pro přidání balíčků NuGet:

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

Microsoft.AspNetCore.Diagnostics.EntityFrameworkCorebalíček NuGet poskytuje ASP.NET Core middlewaru pro EF Core chybové stránky. Tento middleware pomáhá detekovat a diagnostikovat chyby pomocí EF Core migrace.

Informace o dalších poskytovatelích databází, které jsou k dispozici pro EF Core, najdete v tématu poskytovatelé databáze.

Vytvoření datového modelu

Pro tuto aplikaci se vytvoří tyto třídy entit:

Kurz – registrace – diagram datového modelu studenta

Předchozí entity mají následující vztahy:

  • Vztah 1: n mezi Student Enrollment entitami a. Student se může zaregistrovat v jakémkoli počtu kurzů.
  • Vztah 1: n mezi Course Enrollment entitami a. Kurz může mít zaregistrovaný libovolný počet studentů.

V následujících oddílech je vytvořena třída pro každou z těchto entit.

Entita studenta

Diagram entity studenta

Ve složce modely vytvořte Student třídu s následujícím kódem:

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

IDVlastnost je sloupec primárního klíče (PK) tabulky databáze, která odpovídá této třídě. Ve výchozím nastavení rozhraní EF interpretuje vlastnost s názvem ID nebo classnameID jako primární klíč. Například může být název PK pojmenován StudentID spíše než ID .

EnrollmentsVlastnost je navigační vlastnost. Navigační vlastnosti obsahují další entity, které se vztahují k této entitě. EnrollmentsVlastnost Student entity:

  • Obsahuje všechny Enrollment entity, které se vztahují k dané Student entitě.
  • Pokud konkrétní Student řádek v databázi obsahuje dva související Enrollment řádky:
    • Student Enrollments Vlastnost navigace této entity obsahuje tyto dvě Enrollment entity.

Enrollment řádky obsahují hodnotu PK studenta ve StudentID sloupci cizího klíče (FK).

Pokud navigační vlastnost může obsahovat více entit:

  • Typ musí být seznam, například, ICollection<T> List<T> nebo HashSet<T> .
  • Entity je možné přidávat, odstraňovat a aktualizovat.

Křížové relace m:n a 1: n můžou obsahovat víc entit. ICollection<T>Je-li použit, EF vytvoří HashSet<T> ve výchozím nastavení kolekci.

Entita registrace

Diagram entity registrace

Ve složce modely vytvořte Enrollment třídu s následujícím kódem:

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

EnrollmentIDVlastnost je PK. Tato entita používá classnameID vzor namísto ID samotného. StudentEntita použila ID vzor. Někteří vývojáři dávají přednost jednomu vzoru v rámci datového modelu. V tomto kurzu variace znázorňuje, že lze použít vzor. V pozdějším kurzu se dozvíte, jak používat ID bez ClassName, usnadňuje implementaci dědičnosti v datovém modelu.

GradeVlastnost je enum . ?Po Grade deklaraci typu označuje, že Grade vlastnost může mít hodnotu null. nullJe odlišná od nulové třídy. null znamená, že známka není známá nebo ještě není přiřazená.

StudentIDVlastnost je cizí klíč (FK) a odpovídající navigační vlastnost je Student . EnrollmentEntita je přidružená k jedné Student entitě, takže vlastnost může uchovávat jenom jednu Student entitu. To se liší od Student.Enrollments navigační vlastnosti, která může obsahovat více Enrollment entit.

CourseIDVlastnost je FK a odpovídající navigační vlastnost je Course . EnrollmentEntita je přidružená k jedné Course entitě.

Entity Framework interpretuje vlastnost jako vlastnost FK, pokud se nazývá název vlastnosti < Navigace název vlastnosti >< primárního klíče > . Například pro StudentID vlastnost Student navigace, protože pk entity je Student ID . Vlastnosti FK mohou být pojmenovány také < jako název vlastnosti primárního klíče > . Například vzhledem CourseID k tomu, Course že pk entity je CourseID .

Entita Course

Diagram entit kurzu

Ve složce Models vytvořte třídu Course s následujícím kódem:

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 je vysvětlený v pozdějším kurzu. Tento atribut umožňuje zadat pk pro kurz a negeneruje ji databáze.

Vytvoření kontextu databáze

Hlavní třída, která koordinuje funkce EF pro daný datový model, je DbContext třída kontextu databáze. Tato třída je vytvořena odvozením z Microsoft.EntityFrameworkCore.DbContext třídy . Odvozená DbContext třída určuje, které entity jsou zahrnuty v datovém modelu. Některé chování EF je možné přizpůsobit. V tomto projektu má třída název SchoolContext .

Ve složce projektu vytvořte složku s názvem Data .

Ve složce Data vytvořte třídu SchoolContext s následujícím kódem:

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

Předchozí kód vytvoří vlastnost DbSet pro každou sadu entit. Terminologie EF:

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

Příkazy DbSet<Enrollment> DbSet<Course> a by mohly být vynechány a fungovaly by stejně. Ef by je implicitně zahrnoval, protože:

  • Entita Student odkazuje na Enrollment entitu.
  • Entita Enrollment odkazuje na Course entitu.

Při vytvoření databáze ef vytvoří tabulky, které mají stejné názvy jako DbSet názvy vlastností. Názvy vlastností kolekcí jsou obvykle v množném čísle. Například místo Students Student . Vývojáři se neshodují ohledně toho, jestli by názvy tabulek měly nebo nemají být pluralizované. Pro tyto kurzy se výchozí chování přepíše zadáním názvů singelárních tabulek v DbContext . Za poslední vlastnost DbSet přidejte následující zvýrazněný kód.

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

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

Registrace SchoolContext

ASP.NET Core zahrnuje injektáž závislostí. Služby, jako je například kontext databáze EF, se při spuštění aplikace zaregistrované pomocí injektáže závislostí. Komponenty, které vyžadují tyto služby, jako jsou kontrolery MVC, jsou tyto služby poskytovány prostřednictvím parametrů konstruktoru. Kód konstruktoru kontroleru, který získá instanci kontextu, se zobrazí dále v tomto kurzu.

Pokud se SchoolContext chcete zaregistrovat jako služba, otevřete Startup.cs a přidejte zvýrazněné řádky do ConfigureServices metody .

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

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

        public IConfiguration Configuration { get; }

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

            services.AddControllersWithViews();
        }

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

Otevřete soubor appsettings.json a přidejte připojovací řetězec, jak je znázorněno v následujícím kódu:

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

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

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

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

    services.AddDatabaseDeveloperPageExceptionFilter();

    services.AddControllersWithViews();
}

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

SQL Server Express LocalDB

Připojovací řetězec určuje SQL Server LocalDB. LocalDB je odlehčená verze databázového stroje SQL Server Express je určená pro vývoj aplikací, nikoli pro použití v produkčním prostředí. LocalDB se spustí na vyžádání a spustí se v uživatelském režimu, takže neexistuje žádná složitá konfigurace. LocalDB ve výchozím nastavení vytvoří v adresáři soubory .mdf C:/Users/<user> DB.

Inicializace databáze s testovacími daty

EF vytvoří prázdnou databázi. V této části se přidá metoda, která se volá po vytvoření databáze, aby se do ní zapsadala testovací data.

Metoda EnsureCreated se používá k automatickému vytvoření databáze. V pozdějším kurzuuvidíte, jak zpracovávat změny modelu pomocí Migrace Code First ke změně schématu databáze místo vyhození a opětovného vytvoření databáze.

Ve složce Data vytvořte novou třídu s názvem DbInitializer s následujícím kódem:

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

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

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

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

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

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

Předchozí kód zkontroluje, jestli databáze existuje:

  • Pokud se databáze nenašla,
    • Vytvoří se a načte s testovacími daty. Za účelem optimalizace výkonu načítá testovací data do polí, nikoli List<T> do kolekcí.
  • Pokud je databáze nalezena, nevede k žádné akci.

Aktualizujte soubor Program.cs následujícím kódem:

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

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

            CreateDbIfNotExists(host);

            host.Run();
        }

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

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

Program.cs při spuštění aplikace udělá toto:

  • Získejte instanci kontextu databáze z kontejneru injektáže závislostí.
  • Zavolejte DbInitializer.Initialize metodu .
  • Po dokončení metody Initialize odstraňte kontext, jak je znázorněno v následujícím kódu:
public static void Main(string[] args)
{
     var host = CreateWebHostBuilder(args).Build();

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

    host.Run();
}

Při prvním spuštění aplikace se databáze vytvoří a načte s testovacími daty. Při každé změně datového modelu:

  • Odstraňte databázi.
  • Aktualizujte počáteční metodu a začněte znovu s novou databází.

V dalších kurzech se databáze změní při změně datového modelu bez odstranění a opětovného vytvoření. Při změně datového modelu se neztratí žádná data.

Vytvoření kontroleru a zobrazení

Pomocí modulu generování uživatelského rozhraní v Visual Studio přidejte kontroler MVC a zobrazení, která budou používat EF k dotazování a ukládání dat.

Automatické vytváření metod a zobrazení akcí CRUD se označuje jako generování uživatelského rozhraní.

  • V Průzkumník řešení klikněte pravým tlačítkem na složku a vyberte Add > New Scaffolded Item (Přidat novou vy Controllers scaffolded Item).
  • V dialogovém okně Přidat uživatelské rozhraní:
    • Vyberte kontroler MVC se zobrazeními pomocí Entity Framework.
    • Klikněte na Přidat. Zobrazí se dialogové okno Přidat kontroler MVC se zobrazeními Entity Framework uživatelského rozhraní:  Scaffold Student
    • V části Model class(Třída modelu) vyberte Student.
    • V části Třída kontextu dat vyberte SchoolContext.
    • Jako název přijměte výchozí StudentsController.
    • Klikněte na Přidat.

Modul Visual Studio generování uživatelského rozhraní vytvoří soubor a sadu zobrazení StudentsController.cs *.cshtml (souborů), které pracují s kontroleru.

Všimněte si, že SchoolContext kontroler přebírá jako parametr konstruktoru .

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

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

ASP.NET Core závislostí se postará o předání instance SchoolContext do kontroleru. Nakonfigurovali jste to ve Startup třídě .

Kontroler obsahuje Index metodu akce, která zobrazuje všechny studenty v databázi. Metoda získá seznam studentů z entity Students nastavené tak, že si načte Students vlastnost instance kontextu databáze:

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

Asynchronní programovací prvky v tomto kódu jsou vysvětleny dále v tomto kurzu.

Zobrazení Views/Students/Index.cshtml zobrazí tento seznam v tabulce:

@model IEnumerable<ContosoUniversity.Models.Student>

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

<h2>Index</h2>

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

Stisknutím kombinace kláves CTRL+F5 spusťte projekt nebo v nabídce > Spustit bez ladění.

Kliknutím na kartu Students (Studenti) zobrazíte testovací data, která DbInitializer.Initialize metoda vložila. V závislosti na tom, jak úzké je okno prohlížeče, se v horní části stránky zobrazí odkaz na kartu nebo budete muset kliknout na navigační ikonu v pravém horním rohu, abyste odkaz Students viděli.

Zúžit domovskou stránku Contoso University

Stránka Indexu studentů

Zobrazení databáze

Při spuštění aplikace volá DbInitializer.Initialize metoda EnsureCreated . Ef viděl, že neexistuje žádná databáze:

  • Proto vytvořil databázi.
  • InitializeKód metody naplnil databázi daty.

k zobrazení databáze v Visual Studio použijte SQL Server Průzkumník objektů (SSOX):

  • v Visual Studio nabídce zobrazení vyberte SQL Server Průzkumník objektů .
  • V SSOX vyberte (LocalDB) \MSSQLLocalDB > databáze.
  • Vyberte ContosoUniversity1 položku pro název databáze, která je v připojovacím řetězci v appsettings.json souboru.
  • Rozbalte uzel tabulky , aby se zobrazily tabulky v databázi.

Tabulky v SSOX

Kliknutím pravým tlačítkem myši na tabulku student a kliknutím na Zobrazit data zobrazíte data v tabulce.

Tabulka studenta v SSOX

*.mdf *.ldf Soubory databáze a jsou ve složce C:\Users \ <username> .

Protože EnsureCreated je volána v inicializační metodě, která je spuštěna při spuštění aplikace, můžete:

  • Proveďte změnu Student třídy.
  • Odstraňte databázi.
  • Zastavte a spusťte aplikaci. Databáze se automaticky znovu vytvoří, aby se změny shodovala.

Například pokud EmailAddress je vlastnost přidána do Student třídy, nový EmailAddress sloupec v znovu vytvořené tabulce. Zobrazení nezobrazuje novou EmailAddress vlastnost.

Konvence

Množství kódu napsaného v pořadí, v jakém má EF vytvořit úplnou databázi, je minimální, protože použití pravidel EF používá:

  • Názvy DbSet vlastností se používají jako názvy tabulek. Pro entity, na které není odkazováno pomocí DbSet vlastnosti, se názvy tříd entit používají jako názvy tabulek.
  • Názvy vlastností entit se používají pro názvy sloupců.
  • Vlastnosti entity, které jsou pojmenovány ID nebo classnameID jsou rozpoznány jako vlastnosti PK.
  • Vlastnost je interpretována jako vlastnost FK, pokud se nazývá název vlastnosti < Navigace název >< vlastnosti PK > . Například StudentID pro Student vlastnost navigace, protože je v prvku Student PK ID . Vlastnosti FK mohou mít také < název vlastnosti primárního klíče > . Například EnrollmentID vzhledem k tomu, že Enrollment je PK entity EnrollmentID .

Konvenční chování se dá přepsat. Například názvy tabulek lze explicitně zadat, jak je uvedeno výše v tomto kurzu. Názvy sloupců a libovolné vlastnosti lze nastavit jako PK nebo FK.

Asynchronní kód

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

Na webovém serveru je k dispozici omezený počet vláken a v situacích vysokého zatížení se mohou používat všechna dostupná vlákna. Pokud k tomu dojde, server nemůže zpracovat nové požadavky, dokud nebudou vlákna uvolněna. Pomocí synchronního kódu může být mnoho vláken svázáno s tím, že ve skutečnosti neprovádí žádnou práci, protože čeká na dokončení vstupně-výstupních operací. V případě asynchronního kódu, když proces čeká na dokončení vstupně-výstupních operací, je jeho vlákno uvolněno na server, který bude použit pro zpracování jiných požadavků. Výsledkem je, že asynchronní kód umožňuje efektivnější použití prostředků serveru a server je povolen pro zpracování většího objemu dat bez prodlev.

Asynchronní kód zavádí malé množství režie za běhu, ale u situací s nízkým objemem provozu je dosaženo zanedbatelného výkonu, zatímco v případě vysoké situace v provozu je potenciální zlepšení výkonu značné.

V následujícím kódu,, async , Task<T> await a ToListAsync proveďte asynchronní spouštění kódu.

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
  • asyncKlíčové slovo instruuje kompilátor, aby vygeneroval zpětná volání pro části těla metody a automaticky vytvořila Task<IActionResult> vrácený objekt.
  • Návratový typ Task<IActionResult> představuje průběžnou práci s výsledkem typu IActionResult .
  • awaitKlíčové slovo způsobí, že kompilátor rozdělí metodu do dvou částí. První část končí asynchronně spuštěnou operací. Druhá část je vložena do metody zpětného volání, která je volána po dokončení operace.
  • ToListAsync je asynchronní verze ToList metody rozšíření.

Některé věci, které je potřeba znát při psaní asynchronního kódu, který používá EF:

  • Asynchronně jsou spouštěny pouze příkazy, které způsobují odeslání dotazů nebo příkazů do databáze. Který obsahuje například,, ToListAsync SingleOrDefaultAsync a SaveChangesAsync . Neobsahuje například příkazy, které pouze mění IQueryable , například var students = context.Students.Where(s => s.LastName == "Davolio") .
  • Kontext EF není bezpečný pro přístup z více vláken: Nepokoušejte se souběžně provádět více operací. Při volání jakékoli asynchronní metody EF vždy použijte await klíčové slovo.
  • Chcete-li využít výhod výkonu asynchronního kódu, zajistěte, aby všechny použité balíčky knihovny používaly také Async, pokud volají jakékoli metody EF, které způsobují odesílání dotazů do databáze.

Další informace o asynchronním programování v rozhraní .NET naleznete v tématu Async Overview.

Omezení načtených entit

Informace o omezení počtu entit vrácených z dotazu najdete v tématu věnovaném důležitým informacím o výkonu.

SQL Protokolování Entity Framework Core

Konfiguraci protokolování obvykle poskytuje část Logging nastavení aplikace. {Environment} Soubory .json. Pokud chcete SQL příkazy, "Microsoft.EntityFrameworkCore.Database.Command": "Information" přidejte je doappsettings.Development.json:

{
  "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 SQL příkazové řádky a v okně výstupu Visual Studio kódu.

Další informace najdete v tématu a Protokolování v .NET Core a ASP.NET Core o tomto GitHub.

Přejděte k dalšímu kurzu, kde se dozvíte, jak provádět základní operace CRUD (vytváření, čtení, aktualizace, odstranění).

V tomto kurzu se ASP.NET Core MVC a Entity Framework Core s kontrolery a zobrazeními. Razor Pages je alternativní programovací model. Pro nový vývoj doporučujeme Pages Razor over MVC s kontrolery a zobrazeními. Podívejte se Razor na verzi Pages tohoto kurzu. Každý kurz se zabývá některými materiály, které druhý ne:

Tento kurz MVC obsahuje některé věci, které Razor kurz Pages ne:

  • Implementace dědičnosti v datovém modelu
  • Provádění nezpracovaných dotazů SQL
  • Zjednodušení kódu pomocí dynamického LINQ

Kurz Razor Pages obsahuje některé věci, které tento kurz ne:

  • Použití metody Select k načtení souvisejících dat
  • Osvědčené postupy pro EF.

ukázková webová aplikace společnosti Contoso University ukazuje, jak vytvářet webové aplikace ASP.NET Core 2,2 MVC pomocí Entity Framework (EF) Core 2,2 a Visual Studio 2017 nebo 2019.

tento kurz se neaktualizoval ASP.NET Core 3,1. aktualizovala se ASP.NET Core 5,0.

Ukázková aplikace je web pro fiktivní univerzitě společnosti Contoso. Zahrnuje funkce, jako je například využití studenta, vytváření kurzu a přiřazení instruktora. Toto je první v sérii kurzů, které vysvětlují, jak vytvořit ukázkovou aplikaci Contoso University od začátku.

Požadavky

Řešení potíží

Pokud narazíte na problém, který nelze vyřešit, můžete řešení obecně najít porovnáním kódu s dokončeným projektem. Seznam běžných chyb a jejich řešení najdete v části věnované řešení potíží v posledním kurzu v řadě. pokud tam nenajdete, co potřebujete, můžete odeslat otázku do StackOverflow.com pro ASP.NET Core nebo EF Core.

Tip

Toto je série 10 kurzů, z nichž každá sestaví na tom, co se děje v předchozích kurzech. Zvažte uložení kopie projektu po každém úspěšném dokončení kurzu. Pak Pokud narazíte na problémy, můžete začít znovu z předchozího kurzu a nemusíte se vrátit na začátek celé řady.

Webová aplikace Contoso University

Aplikace, kterou budete sestavovat v těchto kurzech, je jednoduchý web na univerzitě.

Uživatelé můžou zobrazit a aktualizovat informace o studentech, kurzech a instruktorech. Tady je několik obrazovek, které vytvoříte.

Stránka indexu studentů

Stránka pro úpravy studentů

Vytvoření webové aplikace

  • Otevřete sadu Visual Studio.

  • V nabídce soubor vyberte Nový > Project.

  • V levém podokně vyberte nainstalované > Visual C# > web.

  • vyberte šablonu projektu ASP.NET Core webové aplikace .

  • Jako název zadejte ContosoUniversity a klikněte na OK.

    Dialogové okno Nový projekt

  • počkejte, než se zobrazí dialogové okno nové webové aplikace ASP.NET Core .

  • vyberte .net Core, ASP.NET Core 2,2 a šablonu webová aplikace (Model-zobrazení-kontroler) .

  • Ujistěte se, že je ověřování nastaveno na bez ověřování.

  • Vyberte OK.

    dialog nové Project ASP.NET Core

Nastavení stylu webu

V několika jednoduchých změnách se nastaví nabídka web, rozložení a Domovská stránka.

Otevřete views/Shared/_Layout. cshtml a proveďte následující změny:

  • Změňte všechny výskyty "ContosoUniversity" na "contoso University". Existují tři výskyty.

  • Přidejte položky nabídky pro, studenty, kurzy, instruktory a oddělení a odstraňte Privacy položku nabídky.

Změny jsou zvýrazněny.

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

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

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

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

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

V souboru Views/ Home /Index.cshtml nahraďte obsah souboru následujícím kódem, který nahradí text o ASP.NET a MVC textem o této aplikaci:

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

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

Stisknutím kombinace kláves CTRL+F5 spusťte projekt nebo v nabídce > Spustit bez ladění. Zobrazí se domovská stránka s kartami stránek, které vytvoříte v těchto kurzech.

Domovská stránka Univerzity Contoso

Informace EF Core NuGet balíčky

Pokud chcete EF Core podporu pro projekt, nainstalujte poskytovatele databáze, na kterého chcete cílit. Tento kurz používá SQL Server a balíček zprostředkovatele je Microsoft.EntityFrameworkCore.SqlServer. Tento balíček je součástí balíčku Microsoft.AspNetCore.App,takže na balíček nemusíte odkazovat.

Balíček EF SQL Server a jeho závislosti ( a Microsoft.EntityFrameworkCore ) poskytují podporu modulu runtime pro Microsoft.EntityFrameworkCore.Relational EF. Balíček nástrojů přidáte později v kurzu Migrace.

Informace o jiných poskytovatelích databází, kteří jsou k dispozici pro Entity Framework Core, najdete v tématu Poskytovatelé databází.

Vytvoření datového modelu

Dále vytvoříte třídy entit pro aplikaci Contoso University. Začnete s následujícími třemi entitami.

Diagram studentského datového modelu registrace kurzu

Mezi entitami a existuje relace 1:N a mezi entitami a existuje relace Student Enrollment 1:N. Course Enrollment Jinými slovy, student může být zaregistrovaný v libovolném počtu kurzů a v kurzu může být zaregistrovaný libovolný počet studentů.

V následujících částech vytvoříte třídu pro každou z těchto entit.

Entita Student

Diagram entit studenta

Ve složce Models vytvořte soubor třídy s názvem Student.cs a nahraďte kód šablony následujícím kódem.

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 databázové tabulky, který odpovídá této třídě. Ve výchozím nastavení interpretuje Entity Framework vlastnost s názvem ID nebo classnameID jako primární klíč.

Vlastnost Enrollments je navigační vlastnost. Vlastnosti navigace uchová další entity, které s touto entitou souvisejí. V tomto případě bude vlastnost obsahovat všechny entity, které souvisejí Enrollments s touto Student entity Enrollment Student entitou. Jinými slovy, pokud má řádek v databázi dva související řádky (řádky, které obsahují hodnotu primárního klíče studenta ve sloupci cizího klíče StudentID), bude navigační vlastnost této entity obsahovat tyto dvě Student Enrollment Student Enrollments Enrollment entity.

Pokud navigační vlastnost může obsahovat více entit (například v relacích M:N nebo 1:N), musí být jejím typem seznam, ve kterém lze položky přidávat, odstraňovat a aktualizovat, například ICollection<T> . Můžete ICollection<T> zadat nebo typ, jako je List<T> nebo HashSet<T> . Pokud zadáte ICollection<T> , EF vytvoří ve výchozím nastavení HashSet<T> kolekci.

Entita Registrace

Diagram entit registrace

Ve složce Models vytvořte soubor Enrollment.cs a nahraďte existující kód následujícím kódem:

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 bude primárním klíčem; tato entita používá vzor místo sebe sama, EnrollmentID jak jste viděli v classnameID ID Student entitě. Obvykle zvolíte jeden vzor a použijete ho v celém datovém modelu. Variace zde ukazuje, že můžete použít který chcete. V pozdějším kurzuuvidíte, jak použití ID bez názvu třídy usnadňuje implementaci dědičnosti v datovém modelu.

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

Vlastnost StudentID je cizí klíč a odpovídající navigační vlastnost je Student . Entita je přidružená k jedné entitě, takže vlastnost může obsahovat jenom jednu entitu (na rozdíl od navigační vlastnosti, kterou jste viděli dříve, která může obsahovat Enrollment Student více Student Student.Enrollments Enrollment entit).

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

Entity Framework vlastnost jako vlastnost cizího klíče, pokud je pojmenována (například pro navigační vlastnost, protože primárním klíčem entity <navigation property name><primary key property name> StudentID je Student Student ID ). Vlastnosti cizího klíče mohou být také pojmenovány jednoduše (například protože primární klíč entity <primary key property name> CourseID je Course CourseID ).

Entita Course

Diagram entit kurzu

Ve složce Models vytvořte Course.cs a nahraďte existující kód následujícím kódem:

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.

O atributu se více DatabaseGenerated řekneme v pozdějším kurzu této série. V podstatě vám tento atribut umožňuje zadat primární klíč pro kurz místo toho, aby ho databáze vygenerovala.

Vytvoření kontextu databáze

Hlavní třída, která koordinuje Entity Framework funkce pro daný datový model, je třída kontextu databáze. Tuto třídu vytvoříte odvozením z Microsoft.EntityFrameworkCore.DbContext třídy . V kódu určíte, které entity jsou zahrnuty do datového modelu. Můžete také přizpůsobit určité Entity Framework chování. V tomto projektu má třída název SchoolContext .

Ve složce projektu vytvořte složku s názvem Data.

Ve složce Data vytvořte nový soubor třídy s názvem SchoolContext.cs a nahraďte kód šablony následujícím kódem:

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

Tento kód vytvoří vlastnost DbSet pro každou sadu entit. V Entity Framework terminologii sada entit obvykle odpovídá databázové tabulce a entita odpovídá řádku v tabulce.

Mohli byste vynechat příkazy DbSet<Enrollment> a DbSet<Course> a to by fungovalo stejně. Typ Entity Framework by je implicitně zahrnoval, protože entita odkazuje na entitu a Student Enrollment Enrollment entita odkazuje na Course entitu.

Při vytvoření databáze ef vytvoří tabulky, které mají stejné názvy jako DbSet názvy vlastností. Názvy vlastností kolekcí jsou obvykle v množném čísle (Studenti místo Student), ale vývojáři nesouhlasí, jestli by názvy tabulek měly nebo nemají být pluralizovány. V těchto kurzech přepíšete výchozí chování zadáním názvů tabulkových tabulek v objektu DbContext. Za poslední vlastnost DbSet přidejte následující zvýrazněný kód.

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

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

Sestavte projekt jako kontrolu chyb kompilátoru.

Registrace SchoolContext

ASP.NET Core implementuje injektáž závislostí. Služby (například kontext databáze EF) se při spuštění aplikace zaregistrované pomocí injektáže závislostí. Komponenty, které vyžadují tyto služby (například kontrolery MVC), jsou tyto služby poskytovány prostřednictvím parametrů konstruktoru. Později v tomto kurzu se zobrazí kód konstruktoru kontroleru, který získá instanci kontextu.

Pokud se SchoolContext chcete zaregistrovat jako služba, otevřete Startup.cs a přidejte zvýrazněné řádky do ConfigureServices metody .

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

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

    services.AddMvc();
}

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

Přidejte příkazy pro obory názvů a a using pak ContosoUniversity.Data Microsoft.EntityFrameworkCore sestavte projekt.

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

Otevřete soubor appsettings.json a přidejte připojovací řetězec, jak je znázorněno v následujícím příkladu.

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

SQL Server Express LocalDB

Připojovací řetězec určuje SQL Server LocalDB. LocalDB je odlehčená verze databázového stroje SQL Server Express je určená pro vývoj aplikací, nikoli pro použití v produkčním prostředí. LocalDB se spustí na vyžádání a spustí se v uživatelském režimu, takže neexistuje žádná složitá konfigurace. LocalDB ve výchozím nastavení vytvoří v adresáři databázové soubory C:/Users/<user> .mdf.

Inicializace databáze s testovacími daty

Aplikace Entity Framework pro vás vytvoří prázdnou databázi. V této části napíšete metodu, která se volá po vytvoření databáze, abyste ji mohli naplnit testovacími daty.

Tady použijete EnsureCreated metodu k automatickému vytvoření databáze. V pozdějším kurzu uvidíte, jak zpracovávat změny modelu pomocí Migrace Code First ke změně schématu databáze místo vyhození a opětovného vytvoření databáze.

Ve složce Data vytvořte nový soubor třídy s názvem DbInitializer.cs a nahraďte kód šablony následujícím kódem, který v případě potřeby vytvoří databázi a načte testovací data do nové databáze.

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

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

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

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

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

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

Kód zkontroluje, jestli v databázi nejsou studenti, a pokud ne, předpokládá, že databáze je nová a je potřeba ji dosaďte testovacími daty. Za účelem optimalizace výkonu načítá testovací data do polí, nikoli List<T> do kolekcí.

V souboru Program.cs upravte Main metodu tak, aby při spuštění aplikace:

  • Získejte instanci kontextu databáze z kontejneru injektáže závislostí.
  • Zavolejte metodu seed a předáte jí kontext.
  • Jakmile je hotová metoda seed, odstraňte kontext.
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

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

            CreateDbIfNotExists(host);

            host.Run();
        }

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

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

Při prvním spuštění aplikace se databáze vytvoří a předsídí testovacími daty. Při každé změně datového modelu:

  • Odstraňte databázi.
  • Aktualizujte počáteční metodu a stejným způsobem začněte s novou databází.

V dalších kurzech uvidíte, jak upravit databázi při změně datového modelu, aniž byste ji odstranili a znovu vytvářely.

Vytvoření kontroleru a zobrazení

V této části se modul generování uživatelského rozhraní v Visual Studio používá k přidání kontroleru MVC a zobrazení, která budou používat EF k dotazování a ukládání dat.

Automatické vytváření metod a zobrazení akcí CRUD se označuje jako generování uživatelského rozhraní. Generování uživatelského rozhraní se liší od generování kódu v tom, že vygenerovaný kód je výchozí bod, který můžete upravit tak, aby vyhovoval vašim požadavkům, zatímco vygenerovaný kód obvykle neupravíte. Když potřebujete přizpůsobit vygenerovaný kód, použijete částečné třídy nebo kód znovu vygenerujte, když se něco změní.

  • Klikněte pravým tlačítkem na složku Controllers (Kontrolery) v Průzkumník řešení a vyberte Add > New Scaffolded Item (Přidat novou vysípravenou položku).
  • V dialogovém okně Přidat uživatelské rozhraní:
    • Vyberte kontroler MVC se zobrazeními pomocí Entity Framework.
    • Klikněte na Přidat. Zobrazí se dialogové okno Přidat kontroler MVC se zobrazeními Entity Framework uživatelského rozhraní:  Scaffold Student
    • V části Model class (Třída modelu) vyberte Student.
    • V části Třída kontextu dat vyberte SchoolContext.
    • Jako název přijměte výchozí StudentsController.
    • Klikněte na Přidat.

Modul Visual Studio generování uživatelského rozhraní vytvoří soubor StudentsController.cs a sadu zobrazení (soubory .cshtml), které fungují s kontroleru.

Všimněte si, že SchoolContext kontroler přebírá jako parametr konstruktoru .

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

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

ASP.NET Core závislostí se postará o předání instance SchoolContext do kontroleru. Tato možnost byla nakonfigurována v souboru Startup.cs.

Kontroler obsahuje Index metodu akce, která zobrazuje všechny studenty v databázi. Metoda získá seznam studentů z entity Students nastavené tak, že si načte Students vlastnost instance kontextu databáze:

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

O asynchronních programovacích prvcích v tomto kódu se dozvíte později v tomto kurzu.

Zobrazení Views/Students/Index.cshtml zobrazí v tabulce tento seznam:

@model IEnumerable<ContosoUniversity.Models.Student>

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

<h2>Index</h2>

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

Stisknutím kombinace kláves CTRL+F5 spusťte projekt nebo v nabídce > Spustit bez ladění.

Kliknutím na kartu Students (Studenti) zobrazíte testovací data, která DbInitializer.Initialize metoda vložila. V závislosti na tom, jak úzké je okno prohlížeče, se v horní části stránky zobrazí odkaz na kartu nebo budete muset kliknout na navigační ikonu v pravém horním rohu, abyste odkaz Students viděli.

Zúžit domovskou stránku Contoso University

Stránka Indexu studentů

Zobrazení databáze

Při spuštění aplikace volá DbInitializer.Initialize metoda EnsureCreated . Ef viděl, že databáze neexistuje, a proto ji vytvořila, a zbytek kódu metody naplní databázi Initialize daty. Pomocí SQL Server Průzkumník objektů (SSOX) můžete zobrazit databázi v Visual Studio.

Zavřete prohlížeč.

Pokud okno SSOX ještě není otevřené, vyberte ho v nabídce Zobrazení v Visual Studio.

V SSOX klikněte na (localdb)\MSSQLLocalDB > Databases a potom klikněte na položku pro název databáze, který je v připojovacím appsettings.json řetězci v souboru.

Rozbalte uzel Tabulky a zobrazte tabulky v databázi.

Tabulky v SSOX

Klikněte pravým tlačítkem na tabulku Student a kliknutím na Zobrazit data zobrazte vytvořené sloupce a řádky vložené do tabulky.

Tabulka studentů v SSOX

Soubory databáze .mdf a .ldf jsou ve složce C:\Users. \ <username>

Vzhledem k tomu, že voláte metodu inicializátoru, která se spouští při spuštění aplikace, můžete teď provést změnu třídy, odstranit databázi, znovu spustit aplikaci a databáze by se automaticky znovu vytvořila tak, aby odpovídala vaší EnsureCreated Student změně. Pokud například přidáte vlastnost do třídy , uvidíte nový sloupec EmailAddress Student v znovu vytvořené EmailAddress tabulce.

Konvence

Množství kódu, které jste museli napsat, aby Entity Framework mohla vytvořit úplnou databázi za vás, je minimální, protože se používají konvence nebo předpoklady, které Entity Framework provádí.

  • Názvy DbSet vlastností se používají jako názvy tabulek. U entit, na které vlastnost odkazuje, se názvy tříd entit DbSet používají jako názvy tabulek.
  • Názvy vlastností entit se používají pro názvy sloupců.
  • Vlastnosti entity s názvem ID nebo classnameID se rozpoznané jako vlastnosti primárního klíče.
  • Vlastnost je interpretována jako vlastnost cizího klíče, pokud je pojmenována (například pro vlastnost navigace, protože primární klíč entity <navigation property name><primary key property name> StudentID je Student Student ID ). Vlastnosti cizího klíče mohou být také pojmenovány jednoduše (například , protože primární klíč entity <primary key property name> EnrollmentID je Enrollment EnrollmentID ).

Konvenční chování lze přepsat. Můžete například explicitně zadat názvy tabulek, jak jste viděli dříve v tomto kurzu. A můžete nastavit názvy sloupců a libovolnou vlastnost jako primární klíč nebo cizí klíč, jak uvidíte v pozdějším kurzu této série.

Asynchronní kód

Asynchronní programování je výchozím režimem 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 neuvolnéhodá. U synchronního kódu může být mnoho vláken svázáno, zatímco ve skutečnosti nepracují, protože čekají na dokončení V/V. Když proces čeká na dokončení vstupně-výstupních operací asynchronního kódu, jeho vlákno se uchová, aby server mohl zpracovávat jiné požadavky. Asynchronní kód v důsledku toho umožňuje efektivnější použití serverových prostředků a server může bez zpoždění zpracovávat větší provoz.

Asynchronní kód za běhu přináší malé režijní náklady, ale v situacích s nízkým provozem je dopad na výkon zanedbatelný, zatímco v situacích s vysokým provozem je potenciální zlepšení výkonu značné.

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

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
  • Klíčové slovo říká kompilátoru, aby pro části těla metody vygeneroval zpětná volání a automaticky vytvořil async Task<IActionResult> vrácený objekt.
  • Návratový Task<IActionResult> typ představuje probíhající práci s výsledkem typu IActionResult .
  • Klíčové await slovo způsobí, že kompilátor rozdělí metodu na dvě části. První část končí operací, která se zahájila asynchronně. Druhá část je do metody zpětného volání, která se volá po dokončení operace.
  • ToListAsync je asynchronní verze ToList rozšiřující metody.

Při psaní asynchronního kódu, který používá tento kód, je třeba vědět o Entity Framework:

  • Asynchronně se provádějí pouze příkazy, které způsobují odeslání dotazů nebo příkazů do databáze. To zahrnuje například ToListAsync , SingleOrDefaultAsync a SaveChangesAsync . Nezahrnuje například příkazy, které mění pouze IQueryable objekt , například var students = context.Students.Where(s => s.LastName == "Davolio") .
  • Kontext EF není bezpečný pro přístup z více vláken: nepokoušejte se provádět více operací paralelně. Při volání jakékoli asynchronní metody EF vždy použijte klíčové await slovo .
  • Pokud chcete využít výhody výkonu asynchronního kódu, ujistěte se, že všechny balíčky knihovny, které používáte (například pro stránkování), také použijte asynchronní, pokud volají jakékoli metody Entity Framework, které způsobují odeslání dotazů do databáze.

Další informace o asynchronním programování v .NET najdete v tématu Přehled modifikátoru Async.

Další kroky

V dalším kurzu se dozvíte, jak provádět základní operace CRUD (vytvoření, čtení, aktualizace, odstranění).