Kurz: Začínáme s EF Core webovou aplikací ASP.NET MVC
Tom Dykstra a Rick Anderson
V tomto kurzu se učí 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 Razor Pages přes MVC s kontrolery a zobrazeními. Podívejte se na verzi Razor Pages tohoto kurzu. Každý kurz se zabývá některými materiály, které ostatní kurzy neřeší:
Některé věci, které tento kurz MVC obsahuje, a kurz Razor Pages nikoli:
- Implementace dědičnosti v datovém modelu
- Provádění nezpracovaných dotazů SQL
- Zjednodušení kódu pomocí dynamické technologie LINQ
Některé věci, které kurz Razor Pages obsahuje, ale tento kurz ne:
- Načtení souvisejících dat pomocí metody Select
- Doporučené postupy pro EF
Ukázková webová aplikace Contoso Pro vysokoškoláky ukazuje, jak vytvořit webovou aplikaci ASP.NET Core MVC pomocí Entity Frameworku (EF) Core a sady Visual Studio.
Ukázková aplikace je web fiktivní univerzity Contoso. Zahrnuje funkce, jako je přijetí studentů, vytváření kurzů a zadání instruktora. Toto je první v řadě kurzů, které vysvětlují, jak sestavit ukázkovou aplikaci Contoso University.
Požadavky
- Pokud s ASP.NET Core MVC teprve začínáte, projděte si sérii kurzů Začínáme s ASP.NET Core MVC , než začnete s touto verzí.
- Sada Visual Studio 2022 se sadou funkcí Vývoj pro ASP.NET a web
- Sada .NET 6.0 SDK
Tento kurz nebyl aktualizován pro ASP.NET Core 6 nebo novější. Pokyny kurzu nebudou fungovat správně, pokud vytvoříte projekt, který cílí na ASP.NET Core 6 nebo novějším. Například webové šablony ASP.NET Core 6 a novější používají minimální model hostování, který se sjednocuje Startup.cs
do Program.cs
jednoho Program.cs
souboru.
Dalším rozdílem zavedeným v .NET 6 je funkce NRT (odkazové typy s možnou hodnotou null). Šablony projektů tuto funkci ve výchozím nastavení povolují. K problémům může dojít v případě, že ef považuje vlastnost za požadovanou v .NET 6, která má hodnotu null v .NET 5. Například stránka Vytvořit studenta selže bezobslužně, pokud Enrollments
není vlastnost nastavena nullable nebo asp-validation-summary
pomocné značky se změní z ModelOnly
na All
.
Pro účely tohoto kurzu doporučujeme nainstalovat a používat sadu .NET 5 SDK. Dokud se tento kurz neaktualizuje, podívejte se na Razor stránky s Entity Framework Core v ASP.NET Core – kurz 1 z 8 o používání Entity Frameworku s ASP.NET Core 6 nebo novějším.
Databázové stroje
Pokyny pro Visual Studio používají SQL Server LocalDB, verzi SQL Serveru Express, která běží jenom ve Windows.
Řešení problémů a řešení potíží
Pokud narazíte na problém, který nemůžete 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 Řešení potíží posledního kurzu v sérii. Pokud nenajdete, co tam potřebujete, můžete zadat dotaz na StackOverflow.com pro ASP.NET Core nebo EF Core.
Tip
Toto je série 10 kurzů, z nichž každá vychází z toho, co se provádí v předchozích kurzech. Po každém úspěšném dokončení kurzu zvažte uložení kopie projektu. Pokud narazíte na problémy, můžete začít znovu z předchozího kurzu místo návratu na začátek celé série.
Webová aplikace Contoso University
Aplikace vytvořená v těchto kurzech je základní web pro vysokoškoláky.
Uživatelé můžou zobrazit a aktualizovat informace o studentech, kurzech a instruktorech. Tady je několik obrazovek v aplikaci:
Vytvoření webové aplikace
- Spusťte Visual Studio a vyberte Vytvořit nový projekt.
- V dialogovém okně Vytvořit nový projekt vyberte ASP.NET Další webová aplikace>Core.
- V dialogovém okně Konfigurovat nový projekt zadejte
ContosoUniversity
název projektu. Je důležité použít tento přesný název včetně velkých písmen, takže se každý z nichnamespace
shoduje při zkopírování kódu. - Vyberte Vytvořit.
- V dialogovém okně Vytvořit novou webovou aplikaci ASP.NET Core vyberte:
- .NET Core a ASP.NET Core 5.0 v rozevíracích sadě
- ASP.NET základní webová aplikace (model-view-controller).
- Vytvořit
Nastavení stylu webu
Několik základních změn nastaví nabídku webu, rozložení a home stránku.
Otevřete Views/Shared/_Layout.cshtml
a proveďte následující změny:
- Změňte každý výskyt
ContosoUniversity
naContoso University
. Existují tři výskyty. - Přidejte položky nabídky pro informace, studenty, kurzy, instruktory a oddělení a odstraňte Privacy položku nabídky.
Předchozí změny jsou zvýrazněné 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.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">
© 2020 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Nahraďte Views/Home/Index.cshtml
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 »</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 »</a></p>
</div>
</div>
Stisknutím kombinace kláves CTRL+F5 spusťte projekt nebo v nabídce zvolte > Spustit ladění bez ladění. Stránka home se zobrazí s kartami pro stránky vytvořené v tomto kurzu.
EF Core Balíčky NuGet
Tento kurz používá SQL Server a balíček zprostředkovatele je Microsoft.EntityFrameworkCore.SqlServer.
Balíček EF SQL Serveru a jeho závislosti Microsoft.EntityFrameworkCore
a Microsoft.EntityFrameworkCore.Relational
poskytuje podporu modulu runtime pro EF.
Přidejte balíček NuGet 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
Balíček Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
NuGet poskytuje ASP.NET middlewaru Core pro EF Core chybové stránky. Tento middleware pomáhá zjišťovat a diagnostikovat chyby při EF Core migracích.
Informace o jiných zprostředkovatelů databáze, které jsou k dispozici EF Core, naleznete v tématu Zprostředkovatelé databáze.
Vytvoření datového modelu
Pro tuto aplikaci se vytvoří následující třídy entit:
Předchozí entity mají následující relace:
- Vztah 1:N mezi
Student
entitami aEnrollment
entitami. Student může být zapsán do libovolného počtu kurzů. - Vztah 1:N mezi
Course
entitami aEnrollment
entitami. Kurz může mít v něm zaregistrovaný libovolný počet studentů.
V následujících částech se vytvoří třída pro každou z těchto entit.
Entita Student
Ve složce Models 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; }
}
}
Vlastnost ID
je sloupec primárního klíče (PK) tabulky databáze, která odpovídá této třídě. Ef ve výchozím nastavení interpretuje vlastnost, která je pojmenovaná ID
nebo classnameID
jako primární klíč. Například PK může být pojmenována StudentID
spíše než ID
.
Vlastnost Enrollments
je navigační vlastnost. Vlastnosti navigace obsahují další entity, které souvisejí s touto entitou. Vlastnost Enrollments
Student
entity:
- Obsahuje všechny
Enrollment
entity, které souvisejí s danouStudent
entitou. - Pokud má konkrétní
Student
řádek v databázi dva souvisejícíEnrollment
řádky:Student
Navigační vlastnost této entityEnrollments
obsahuje tyto dvěEnrollment
entity.
Enrollment
Řádky obsahují hodnotu PK studenta ve sloupci cizího StudentID
klíče (FK).
Pokud navigační vlastnost může obsahovat více entit:
- Typ musí být seznam, například
ICollection<T>
,List<T>
neboHashSet<T>
. - Entity je možné přidávat, odstraňovat a aktualizovat.
Relace navigace M:N a 1:N můžou obsahovat více entit. Když ICollection<T>
se použije, EF ve výchozím nastavení vytvoří kolekci HashSet<T>
.
Entita Registrace
Ve složce Models 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; }
}
}
Vlastnost EnrollmentID
je PK. Tato entita classnameID
používá vzor místo ID
sebe sama. Entita Student
použila ID
vzor. Někteří vývojáři raději používají jeden vzor v celém datovém modelu. V tomto kurzu ukazuje varianta, že lze použít některý ze vzorů. V pozdějším kurzu se dozvíte, jak použití ID
bez názvu třídy usnadňuje implementaci dědičnosti v datovém modelu.
Vlastnost Grade
je .enum
Poté ?
, co Grade
deklarace typu označuje, že Grade
vlastnost je nullable. Známka, která se null
liší od nulové známky. null
znamená, že známka není známa nebo ještě nebyla přiřazena.
Vlastnost StudentID
je cizí klíč (FK) a odpovídající navigační vlastnost je Student
. Entita Enrollment
je přidružená k jedné Student
entitě, takže vlastnost může obsahovat pouze jednu Student
entitu. To se liší od Student.Enrollments
navigační vlastnosti, která může obsahovat více Enrollment
entit.
Vlastnost CourseID
je FK a odpovídající navigační vlastnost je Course
. Entita Enrollment
je přidružená k jedné Course
entitě.
Entity Framework interpretuje vlastnost jako vlastnost FK, pokud má název <
název vlastnosti navigace název><
vlastnosti>
primárního klíče. Například pro Student
navigační vlastnost, StudentID
protože Student
pk entity je ID
. Vlastnosti FK lze také pojmenovat název <
>
vlastnosti primárního klíče. Například proto, CourseID
že Course
pk entity je CourseID
.
Entita Course
Ve složce Models vytvořte Course
třídu 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 počtem Enrollment
entit.
Atribut DatabaseGenerated je vysvětlen v pozdějším kurzu. Tento atribut umožňuje zadat PK pro kurz místo toho, aby ho databáze vygenerovala.
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 do datového 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 s následujícím kódemSchoolContext
:
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ří DbSet
vlastnost pro každou sadu entit. V terminologii EF:
- Sada entit obvykle odpovídá databázové tabulce.
- Entita odpovídá řádku v tabulce.
Příkazy DbSet<Enrollment>
a DbSet<Course>
příkazy by mohly být vynechány a fungovaly by stejně. Ef by je zahrnoval implicitně, protože:
- Entita
Student
odkazuje na entituEnrollment
. - Entita
Enrollment
odkazuje na entituCourse
.
Po vytvoření databáze ef vytvoří tabulky, které mají názvy stejné jako DbSet
názvy vlastností. Názvy vlastností pro kolekce jsou obvykle množné číslo. Například místo Students
Student
. Vývojáři nesouhlasí s tím, jestli mají být názvy tabulek v množném čísle nebo ne. V těchto kurzech je výchozí chování přepsáno zadáním názvů singulárních tabulek v souboru DbContext
. Uděláte to tak, že za poslední vlastnost DbSet přidáte 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");
}
}
}
Zaregistrujte SchoolContext
ASP.NET Core zahrnuje injektáž závislostí. Služby, jako je kontext databáze EF, se během spouštění aplikace registrují pomocí injektáže závislostí. Komponenty, které vyžadují tyto služby, jako jsou kontrolery MVC, jsou 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 chcete zaregistrovat SchoolContext
jako služba, otevřete Startup.cs
a přidejte do ConfigureServices
metody zvýrazněné řádky.
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í řetězec se předává kontextu voláním metody na objektuDbContextOptionsBuilder
. V případě místního vývoje načte konfigurační systém ASP.NET Core připojovací řetězec ze appsettings.json
souboru.
appsettings.json
Otevřete soubor 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
ConfigureServices
Přidejte AddDatabaseDeveloperPageExceptionFilter ho, jak je 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 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 se spouští na vyžádání a spouští se v uživatelském režimu, takže neexistuje složitá konfigurace. Ve výchozím nastavení vytvoří LocalDB v C:/Users/<user>
adresáři soubory .mdf 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 naplnila testovacími daty.
Metoda EnsureCreated
se používá k automatickému vytvoření databáze. V pozdějším kurzu se dozvíte, jak zpracovávat změny modelu pomocí Migrace Code First změnit schéma databáze místo vyřazení 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 databáze nebyla nalezena;
- Vytvoří se a načte s testovacími daty. Načte testovací data do polí, nikoli
List<T>
do kolekcí za účelem optimalizace výkonu.
- Vytvoří se a načte s testovacími daty. Načte testovací data do polí, nikoli
- Pokud se databáze najde, neprochází žádná akce.
Aktualizujte 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
provede při spuštění aplikace následující:
- Získejte instanci kontextu databáze z kontejneru injektáže závislostí.
- Zavolejte metodu
DbInitializer.Initialize
. - Odstraňte kontext po
Initialize
dokončení metody, 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. Kdykoli se datový model změní:
- Odstraňte databázi.
- Aktualizujte počáteční metodu a spusťte afresh s novou databází.
V pozdějších kurzech se databáze upraví 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 sadě 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
Controllers
složku a vyberte Přidat > novou vygenerovanou položku. - V dialogovém okně Přidat generování uživatelského rozhraní :
- Vyberte kontroler MVC se zobrazeními pomocí Entity Frameworku.
- Klikněte na tlačítko Přidat. Zobrazí se dialogové okno Přidat kontroler MVC se zobrazením pomocí entity Framework :
- Ve třídě Model vyberte Student.
- V datovém kontextu třídy vyberte SchoolContext.
- Jako název přijměte výchozí StudentsController .
- Klikněte na tlačítko Přidat.
Modul generování uživatelského rozhraní sady Visual Studio vytvoří StudentsController.cs
soubor a sadu zobrazení (*.cshtml
souborů), které pracují s kontrolerem.
Všimněte si, že kontroler přebírá SchoolContext
jako parametr konstruktoru.
namespace ContosoUniversity.Controllers
{
public class StudentsController : Controller
{
private readonly SchoolContext _context;
public StudentsController(SchoolContext context)
{
_context = context;
}
ASP.NET injektáž závislostí jádra se postará o předání instance SchoolContext
kontroleru. Nakonfigurovali jste ji ve Startup
třídě.
Kontroler obsahuje metodu Index
akce, která zobrazí všechny studenty v databázi. Metoda získá seznam studentů z entity Students nastavenou čtením Students
vlastnosti 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 zvolte > Spustit ladění bez ladění.
Kliknutím na kartu Studenti zobrazíte testovací data vložená metodou DbInitializer.Initialize
. V závislosti na tom, jak je okno prohlížeče úzké, uvidíte Students
odkaz na kartu v horní části stránky nebo budete muset kliknout na ikonu navigace v pravém horním rohu, aby se odkaz zobrazil.
Zobrazení databáze
Po spuštění DbInitializer.Initialize
aplikace volá metoda EnsureCreated
. Ef viděl, že neexistuje žádná databáze:
- Proto se vytvořila databáze.
- Kód
Initialize
metody naplnil databázi daty.
K zobrazení databáze v sadě Visual Studio použijte SQL Server Průzkumník objektů (SSOX):
- V nabídce Zobrazit v sadě Visual Studio vyberte Průzkumník objektů SQL Serveru.
- V nástroji SSOX vyberte databáze (localdb)\MSSQLLocalDB>.
- Vyberte
ContosoUniversity1
položku pro název databáze, která je v připojovací řetězec vappsettings.json
souboru. - Rozbalením uzlu Tabulky zobrazíte tabulky v databázi.
Klikněte pravým tlačítkem myši na tabulku Student a kliknutím na Zobrazit data zobrazte data v tabulce.
Soubory *.mdf
a *.ldf
soubory databáze jsou ve složce C:\Users\<username> .
Protože EnsureCreated
je volána v inicializační metodě, která běží na spuštění aplikace, můžete:
- Proveďte změnu třídy
Student
. - Odstraňte databázi.
- Zastavte a spusťte aplikaci. Databáze se automaticky znovu vytvoří tak, aby odpovídala této změně.
Pokud je například EmailAddress
vlastnost přidána Student
do třídy, nový EmailAddress
sloupec v znovu vytvořené tabulce. Zobrazení nezobrazí novou EmailAddress
vlastnost.
Konvence
Množství kódu napsaného za účelem vytvoření úplné databáze ef je minimální kvůli použití konvencí, které EF používá:
- Názvy
DbSet
vlastností se používají jako názvy tabulek. U entit, naDbSet
které vlastnost neodkazuje, se názvy tříd entit používají jako názvy tabulek. - Názvy vlastností entity se používají pro názvy sloupců.
- Vlastnosti entity, které jsou pojmenovány
ID
neboclassnameID
jsou rozpoznány jako vlastnosti PK. - Vlastnost se interpretuje jako vlastnost FK, pokud se jmenuje
<
název vlastnosti PK názvu><
>
navigační vlastnosti. Například proStudent
navigační vlastnost,StudentID
protožeStudent
pk entity jeID
. Vlastnosti FK lze také pojmenovat název<
>
vlastnosti primárního klíče. Například vzhledem k tomu,EnrollmentID
žeEnrollment
pk entity jeEnrollmentID
.
Konvenční chování lze přepsat. Můžete například explicitně zadat názvy tabulek, jak je znázorněno výše v tomto kurzu. Názvy sloupců a libovolná vlastnost lze nastavit jako PK nebo FK.
Asynchronní kód
Asynchronní programování je výchozí režim pro ASP.NET Core a EF Core.
Webový server má k dispozici omezený počet vláken a v situacích s vysokým zatížením se můžou používat všechna dostupná vlákna. V takovém případě nemůže server zpracovat nové požadavky, dokud se vlákna nevysadí. V synchronním kódu může být mnoho vláken svázané, zatímco ve skutečnosti neprovádí žádnou práci, protože čekají na dokončení vstupně-výstupních operací. Když proces čeká na dokončení vstupně-výstupních operací, v asynchronním kódu se jeho vlákno uvolní, aby server používal ke zpracování dalších požadavků. V důsledku toho asynchronní kód umožňuje efektivnější použití serverových prostředků a server je povolený pro zpracování většího provozu bez zpoždění.
Asynchronní kód zavádí v době běhu malé režijní náklady, ale v situacích s nízkým provozem je dosažení výkonu zanedbatelné, zatímco v situacích s vysokým provozem je potenciální zlepšení výkonu podstatné.
V následujícím kódu , async
, Task<T>
await
asynchronně ToListAsync
provést kód.
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
- Klíčové
async
slovo říká kompilátoru, aby vygeneroval zpětná volání pro části těla metody a aby automaticky vytvořil vrácenýTask<IActionResult>
objekt. - Návratový typ
Task<IActionResult>
představuje probíhající práci s výsledkem typuIActionResult
. - Klíčové
await
slovo způsobí, že kompilátor rozdělí metodu do dvou částí. První část končí operací, která se spouští asynchronně. Druhá část se vloží do metody zpětného volání, která se volá při dokončení operace. ToListAsync
je asynchronní verzeToList
metody rozšíření.
Při psaní asynchronního kódu, který používá EF, 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 například
ToListAsync
, ,SingleOrDefaultAsync
aSaveChangesAsync
. Nezahrnuje například příkazy, které jen mění ,IQueryable
napříkladvar students = context.Students.Where(s => s.LastName == "Davolio")
. - Kontext EF není bezpečný pro vlákno: Nepokoušejte se paralelně provádět více operací. Když voláte jakoukoli asynchronní metodu
await
EF, vždy použijte klíčové slovo. - Pokud chcete využít výhod výkonu asynchronního kódu, ujistěte se, že všechny balíčky knihoven používané také používají asynchronní, pokud volají jakékoli metody EF, které způsobují odesílání dotazů do databáze.
Další informace o asynchronním programování v .NET naleznete v tématu Přehled asynchronního programování.
Omezení načtených entit
Informace o omezení počtu entit vrácených z dotazu najdete v tématu Důležité informace o výkonu.
Protokolování SQL entity Framework Core
Konfiguraci protokolování obvykle zajišťuje oddíl Logging
souborů appsettings.{Environment}.json
. Pokud chcete protokolovat příkazy SQL, přidejte "Microsoft.EntityFrameworkCore.Database.Command": "Information"
do appsettings.Development.json
souboru:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDB-2;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
,"Microsoft.EntityFrameworkCore.Database.Command": "Information"
}
},
"AllowedHosts": "*"
}
V předchozím kódu JSON se příkazy SQL zobrazí na příkazovém řádku a v okně výstupu sady Visual Studio.
Další informace najdete v tématu Protokolování v .NET Core a ASP.NET Core a tento problém na GitHubu.
V dalším kurzu se dozvíte, jak provádět základní operace CRUD (vytvoření, čtení, aktualizace, odstranění).
V tomto kurzu se učí 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 Razor Pages přes MVC s kontrolery a zobrazeními. Podívejte se na verzi Razor Pages tohoto kurzu. Každý kurz se zabývá některými materiály, které ostatní kurzy neřeší:
Některé věci, které tento kurz MVC obsahuje, a kurz Razor Pages nikoli:
- Implementace dědičnosti v datovém modelu
- Provádění nezpracovaných dotazů SQL
- Zjednodušení kódu pomocí dynamické technologie LINQ
Některé věci, které kurz Razor Pages obsahuje, ale tento kurz ne:
- Načtení souvisejících dat pomocí metody Select
- Doporučené postupy pro EF
Ukázková webová aplikace Contoso University ukazuje, jak vytvořit webové aplikace ASP.NET Core 2.2 MVC pomocí Entity Frameworku (EF) Core 2.2 a Visual Studio 2019.
Tento kurz nebyl aktualizován pro ASP.NET Core 3.1. Aktualizoval se pro ASP.NET Core 5.0.
Ukázková aplikace je web fiktivní univerzity Contoso. Zahrnuje funkce, jako je přijetí studentů, vytváření kurzů a zadání instruktora. Toto je první z řady kurzů, které vysvětlují, jak vytvořit ukázkovou aplikaci Contoso University úplně od začátku.
Požadavky
- .NET Core SDK 2.2
- Visual Studio 2019 s následujícími úlohami:
- úloha vývoje pro ASP.NET a web
- Úloha vývoje pro různé platformy .NET Core
Řešení problému
Pokud narazíte na problém, který nemůžete 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 Řešení potíží posledního kurzu v sérii. Pokud nenajdete, co tam potřebujete, můžete zadat dotaz na StackOverflow.com pro ASP.NET Core nebo EF Core.
Tip
Toto je série 10 kurzů, z nichž každá vychází z toho, co se provádí v předchozích kurzech. Po každém úspěšném dokončení kurzu zvažte uložení kopie projektu. Pokud narazíte na problémy, můžete začít znovu z předchozího kurzu místo návratu na začátek celé série.
Webová aplikace Contoso University
Aplikace, kterou budete vytvářet v těchto kurzech, je jednoduchý web pro vysokoškoláky.
Uživatelé můžou zobrazit a aktualizovat informace o studentech, kurzech a instruktorech. Tady je několik obrazovek, které vytvoříte.
Vytvoření webové aplikace
Otevřete sadu Visual Studio.
V nabídce Soubor vyberte Nový > projekt.
V levém podokně vyberte Nainstalovaný > web Visual C#>.
Vyberte šablonu projektu ASP.NET Základní webová aplikace.
Jako název zadejte ContosoUniversity a klikněte na OK.
Počkejte, až se zobrazí dialogové okno Nová webová aplikace ASP.NET Core.
Vyberte .NET Core, ASP.NET Core 2.2 a šablonu Webové aplikace (Model-View-Controller).
Ujistěte se, že je ověřování nastavené na Žádné ověřování.
Vyberte OK.
Nastavení stylu webu
Několik jednoduchých změn nastaví nabídku webu, rozložení a home stránku.
Otevřete Views/Shared/_Layout.cshtml
a proveďte následující změny:
Změňte každý výskyt "ContosoUniversity" na "Contoso University". Existují tři výskyty.
Přidejte položky nabídky pro informace, studenty, kurzy, instruktory a oddělení a odstraňte Privacy položku nabídky.
Změny jsou zvýrazněné.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<environment include="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
crossorigin="anonymous"
integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
</environment>
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<partial name="_CookieConsentPartial" />
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2019 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
</environment>
<environment exclude="Development">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"
asp-fallback-src="~/lib/jquery/dist/jquery.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
</script>
</environment>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
Nahraďte Views/Home/Index.cshtml
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 »</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 »</a></p>
</div>
</div>
Stisknutím kombinace kláves CTRL+F5 spusťte projekt nebo v nabídce zvolte > Spustit ladění bez ladění. home Zobrazí se stránka s kartami pro stránky, které vytvoříte v těchto kurzech.
Informace o EF Core balíčcích NuGet
Pokud chcete do projektu přidat EF Core podporu, nainstalujte zprostředkovatele databáze, 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í metabalíku Microsoft.AspNetCore.App, takže na balíček nemusíte odkazovat.
Balíček EF SQL Serveru a jeho závislosti (Microsoft.EntityFrameworkCore
a Microsoft.EntityFrameworkCore.Relational
) poskytují podporu modulu runtime pro EF. Balíček nástrojů přidáte později v kurzu Migrace .
Informace o jiných zprostředkovatelů databáze, kteří jsou k dispozici pro Entity Framework Core, naleznete v tématu Zprostředkovatelé databáze.
Vytvoření datového modelu
V dalším kroku vytvoříte třídy entit pro aplikaci Contoso University. Začnete následujícími třemi entitami.
Mezi entitami existuje vztah Student
Enrollment
1:N a mezi entitami existuje vztah Course
Enrollment
1:N. Jinými slovy, student může být zapsán do libovolného počtu kurzů a kurz může mít v něm zaregistrovaný libovolný počet studentů.
V následujících částech vytvoříte třídu pro každou z těchto entit.
Entita Student
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 v tabulce databáze, 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 obsahují další entity, které souvisejí s touto entitou. V tomto případě Enrollments
vlastnost objektu Student entity
bude obsahovat všechny Enrollment
entity, které souvisejí s danou Student
entitou. Jinými slovy, pokud Student
má řádek v databázi dva související Enrollment
řádky (řádky, které obsahují hodnotu primárního klíče studenta ve sloupci cizího klíče StudentID), Student
bude navigační vlastnost dané entity Enrollments
obsahovat tyto dvě Enrollment
entity.
Pokud navigační vlastnost může obsahovat více entit (jako v relacích M:N nebo 1:N), musí být jeho typ seznamem, ve kterém lze přidávat, odstraňovat a aktualizovat položky, například ICollection<T>
. Můžete zadat nebo zadat ICollection<T>
typ, například List<T>
nebo HashSet<T>
. Pokud zadáte ICollection<T>
, EF ve výchozím nastavení vytvoří kolekci HashSet<T>
.
Entita Registrace
Ve složce Models vytvořte 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 EnrollmentID
bude primárním klíčem. Tato entita používá classnameID
vzor místo ID
sebe sama, jak jste viděli v entitě Student
. Obvykle byste zvolili jeden vzor a použili ho v celém datovém modelu. V této variantě je znázorněno, že můžete použít některý ze vzorů. V pozdějším kurzu se dozví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
deklaraci typu označuje, že Grade
vlastnost je nullable. Známka, která má hodnotu null, se liší od nulové známky – hodnota null znamená, že známka není známá 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 tato vlastnost může obsahovat pouze jednu Student
entitu (na rozdíl od Student.Enrollments
vlastnosti navigace, kterou jste viděli dříve, což může obsahovat více 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 interpretuje vlastnost jako vlastnost cizího klíče, pokud je pojmenovaná <navigation property name><primary key property name>
(například StudentID
pro Student
navigační vlastnost, protože Student
primární klíč entity je ID
). Vlastnosti cizího klíče lze také pojmenovat jednoduše <primary key property name>
(například proto, CourseID
že Course
primární klíč entity je CourseID
).
Entita Course
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 počtem Enrollment
entit.
Další informace o atributu DatabaseGenerated
si řekneme v pozdějším kurzu této série. Tento atribut v podstatě umožňuje zadat primární klíč pro kurz, nikoli databázi vygenerovat.
Vytvoření kontextu databáze
Hlavní třída, která koordinuje funkce Entity Framework 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 součástí datového modelu. Můžete také přizpůsobit určité chování entity Framework. 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ří DbSet
vlastnost pro každou sadu entit. V terminologii Entity Framework sada entit obvykle odpovídá databázové tabulce a entita odpovídá řádku v tabulce.
Mohli jste vynechat DbSet<Enrollment>
příkazy a DbSet<Course>
příkazy by fungovaly stejně. Entity Framework by je zahrnoval implicitně, protože entita Student
odkazuje na entitu Enrollment
a entitu Enrollment
odkazuje na entitu Course
.
Po vytvoření databáze ef vytvoří tabulky, které mají názvy stejné jako DbSet
názvy vlastností. Názvy vlastností kolekcí jsou obvykle množné číslo (Studenti místo studenta), ale vývojáři nesouhlasí s tím, jestli mají být názvy tabulek v množném čísle nebo ne. V těchto kurzech přepíšete výchozí chování zadáním názvů tabulek s jednotným číslem v dbContext. Uděláte to tak, že za poslední vlastnost DbSet přidáte 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 SchoolContextu
ASP.NET Core ve výchozím nastavení implementuje injektáž závislostí. Služby (například kontext databáze EF) se během spouštění aplikace registrují 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. Uvidíte kód konstruktoru kontroleru, který získá kontextovou instanci později v tomto kurzu.
Pokud se chcete zaregistrovat SchoolContext
jako služba, otevřete Startup.cs
a přidejte do ConfigureServices
metody zvýrazněné řádky.
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í řetězec se předává kontextu voláním metody na objektuDbContextOptionsBuilder
. V případě místního vývoje načte konfigurační systém ASP.NET Core připojovací řetězec ze appsettings.json
souboru.
Přidejte using
příkazy pro ContosoUniversity.Data
obory názvů a Microsoft.EntityFrameworkCore
pak sestavte projekt.
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Http;
appsettings.json
Otevřete soubor 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 databázi SQL Server LocalDB. 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 se spouští na vyžádání a spouští se v uživatelském režimu, takže neexistuje složitá konfigurace. Ve výchozím nastavení vytvoří LocalDB .mdf databázových souborů v C:/Users/<user>
adresáři.
Inicializace databáze s testovacími daty
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, aby se naplnila testovacími daty.
Tady použijete metodu EnsureCreated
k automatickému vytvoření databáze. V pozdějším kurzu se dozvíte, jak zpracovávat změny modelu pomocí Migrace Code First ke změně schématu databáze místo vyřazení 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ý způsobí vytvoření databáze v případě potřeby a načtení testovacích dat 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 žádní studenti, a pokud ne, předpokládá, že je databáze nová a musí být osvědčována testovacími daty. Načte testovací data do polí, nikoli List<T>
do kolekcí za účelem optimalizace výkonu.
V Program.cs
, upravit metodu Main
provést následující při spuštění aplikace:
- Získejte instanci kontextu databáze z kontejneru injektáže závislostí.
- Zavolejte počáteční metodu a předejte jí kontext.
- Při dokončení počáteční metody 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 vytvoří se s testovacími daty. Kdykoli změníte datový model:
- Odstraňte databázi.
- Aktualizujte počáteční metodu a spusťte afresh s novou databází stejným způsobem.
V dalších kurzech se dozvíte, jak upravit databázi, když se datový model změní, aniž byste ji odstranili a znovu vytvořili.
Vytvoření kontroleru a zobrazení
V této části se modul generování uživatelského rozhraní v sadě 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ím bodem, který můžete upravit tak, aby vyhovoval vašim vlastním požadavkům, zatímco vygenerovaný kód obvykle neupravujete. Když potřebujete vygenerovaný kód přizpůsobit, použijete částečné třídy nebo kód znovu vygenerujete při změně.
- Klikněte pravým tlačítkem myši na složku Kontrolery v Průzkumník řešení a vyberte Přidat > novou vygenerovanou položku.
- V dialogovém okně Přidat generování uživatelského rozhraní :
- Vyberte kontroler MVC se zobrazeními pomocí Entity Frameworku.
- Klikněte na tlačítko Přidat. Zobrazí se dialogové okno Přidat kontroler MVC se zobrazením pomocí entity Framework :
- V možnosti Model třída vyberte Student.
- V datovém kontextu třídy vyberte SchoolContext.
- Jako název přijměte výchozí StudentsController .
- Klikněte na tlačítko Přidat.
Modul generování uživatelského rozhraní sady Visual Studio vytvoří StudentsController.cs
soubor a sadu zobrazení (.cshtml
souborů), které pracují s kontrolerem.
Všimněte si, že kontroler přebírá SchoolContext
jako parametr konstruktoru.
namespace ContosoUniversity.Controllers
{
public class StudentsController : Controller
{
private readonly SchoolContext _context;
public StudentsController(SchoolContext context)
{
_context = context;
}
ASP.NET injektáž závislostí jádra se postará o předání instance SchoolContext
kontroleru. To bylo nakonfigurováno v Startup.cs
souboru.
Kontroler obsahuje metodu Index
akce, která zobrazí všechny studenty v databázi. Metoda získá seznam studentů z entity Students nastavenou čtením Students
vlastnosti instance kontextu databáze:
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
Seznámíte se s asynchronními programovacími prvky v tomto kódu 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 zvolte > Spustit ladění bez ladění.
Kliknutím na kartu Studenti zobrazíte testovací data vložená metodou DbInitializer.Initialize
. V závislosti na tom, jak je okno prohlížeče úzké, uvidíte Students
odkaz na kartu v horní části stránky nebo budete muset kliknout na ikonu navigace v pravém horním rohu, aby se odkaz zobrazil.
Zobrazení databáze
Při spuštění aplikace DbInitializer.Initialize
volá metoda EnsureCreated
. EF viděla, že neexistuje žádná databáze, a proto ji vytvořila, a pak zbytek Initialize
kódu metody naplnil databázi daty. K zobrazení databáze v sadě Visual Studio můžete použít SQL Server Průzkumník objektů (SSOX).
Zavřete prohlížeč.
Pokud okno SSOX ještě není otevřené, vyberte ho v nabídce Zobrazení v sadě Visual Studio.
V nástroji SSOX klikněte na databáze (localdb)\MSSQLLocalDB >a potom klikněte na položku názvu databáze, která je v připojovací řetězec v appsettings.json
souboru.
Rozbalením uzlu Tabulky zobrazíte tabulky v databázi.
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.
Soubory databáze .mdf a .ldf jsou ve složce C:\Users\<username> .
Vzhledem k tomu, že voláte EnsureCreated
metodu inicializátoru, která běží na spuštění aplikace, můžete nyní provést změnu Student
třídy, odstranit databázi, spustit aplikaci znovu a databáze se automaticky znovu vytvoří tak, aby odpovídala vaší změně. Pokud například do třídy přidáte EmailAddress
vlastnost Student
, uvidíte v znovu vytvořené tabulce nový EmailAddress
sloupec.
Konvence
Množství kódu, který jste museli napsat, aby Entity Framework mohl vytvořit úplnou databázi za vás, je minimální kvůli použití konvencí nebo předpokladů, které Entity Framework dělá.
- Názvy
DbSet
vlastností se používají jako názvy tabulek. U entit, naDbSet
které vlastnost neodkazuje, se názvy tříd entit používají jako názvy tabulek. - Názvy vlastností entity se používají pro názvy sloupců.
- Vlastnosti entity s názvem ID nebo classnameID jsou rozpoznány jako vlastnosti primárního klíče.
- Vlastnost je interpretována jako vlastnost cizího klíče, pokud se jmenuje název vlastnosti navigace název><vlastnosti> primárního klíče (například
StudentID
proStudent
navigační vlastnost, protožeStudent
primární klíč entity jeID
).< Vlastnosti cizího klíče lze také pojmenovat jednoduše <název> vlastnosti primárního klíče (například vzhledem k tomu,EnrollmentID
žeEnrollment
primární klíč entity jeEnrollmentID
).
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 nastavit 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í režim pro ASP.NET Core a EF Core.
Webový server má k dispozici omezený počet vláken a v situacích s vysokým zatížením se můžou používat všechna dostupná vlákna. V takovém případě nemůže server zpracovat nové požadavky, dokud se vlákna nevysadí. V synchronním kódu může být mnoho vláken svázané, zatímco ve skutečnosti neprovádí žádnou práci, protože čekají na dokončení vstupně-výstupních operací. Když proces čeká na dokončení vstupně-výstupních operací, v asynchronním kódu se jeho vlákno uvolní, aby server používal ke zpracování dalších požadavků. V důsledku toho asynchronní kód umožňuje efektivnější použití serverových prostředků a server je povolený pro zpracování většího provozu bez zpoždění.
Asynchronní kód zavádí v době běhu malé režijní náklady, ale v situacích s nízkým provozem je dosažení výkonu zanedbatelné, zatímco v situacích s vysokým provozem je potenciální zlepšení výkonu podstatné.
V následujícím kódu async
klíčové slovo, Task<T>
návratová hodnota, await
klíčové slovo a ToListAsync
metoda, aby se kód spustil asynchronně.
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
- Klíčové
async
slovo říká kompilátoru, aby vygeneroval zpětná volání pro části těla metody a aby automaticky vytvořil vrácenýTask<IActionResult>
objekt. - Návratový typ
Task<IActionResult>
představuje probíhající práci s výsledkem typuIActionResult
. - Klíčové
await
slovo způsobí, že kompilátor rozdělí metodu do dvou částí. První část končí operací, která se spouští asynchronně. Druhá část se vloží do metody zpětného volání, která se volá při dokončení operace. ToListAsync
je asynchronní verzeToList
metody rozšíření.
Při psaní asynchronního kódu, který používá Entity Framework, 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 například
ToListAsync
, ,SingleOrDefaultAsync
aSaveChangesAsync
. Nezahrnuje například příkazy, které jen mění ,IQueryable
napříkladvar students = context.Students.Where(s => s.LastName == "Davolio")
. - Kontext EF není bezpečný pro vlákno: Nepokoušejte se paralelně provádět více operací. Když voláte jakoukoli asynchronní metodu
await
EF, vždy použijte klíčové slovo. - Pokud chcete využít výhod 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í), použijte také asynchronní, pokud volají nějaké metody Entity Framework, které způsobují odesílání dotazů do databáze.
Další informace o asynchronním programování v .NET naleznete v tématu Přehled asynchronního programování.
Další kroky
V dalším kurzu se dozvíte, jak provádět základní operace CRUD (vytvoření, čtení, aktualizace, odstranění).