Razor Strony z programem Entity Framework Core w ASP.NET Core — samouczek 1 z 8
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Przez Tom Dykstra, Jeremy Likness i Jon P Smith
Jest to pierwszy z serii samouczków, które pokazują, jak używać programu Entity Framework (EF) Core w aplikacji ASP.NET Core Razor Pages . Samouczki tworzą witrynę internetową fikcyjnego uniwersytetu Contoso. Witryna zawiera funkcje, takie jak wstęp dla uczniów, tworzenie kursów i zadania instruktora. W tym samouczku jest używane pierwsze podejście do kodu. Aby uzyskać informacje na temat korzystania z tego samouczka przy użyciu pierwszego podejścia do bazy danych, zobacz ten problem z usługą GitHub.
Pobierz lub wyświetl ukończoną aplikację. Pobierz instrukcje.
Wymagania wstępne
- Jeśli dopiero zaczynasz Razor pracę ze stronami, zapoznaj się z serią samouczków Wprowadzenie do Razor stron przed rozpoczęciem tego samouczka.
- Program Visual Studio 2022 z pakietem roboczym tworzenia aplikacji ASP.NET i aplikacji internetowych.
- Zestaw SDK dla platformy .NET 6.0
Aparaty bazy danych
Instrukcje programu Visual Studio używają programu SQL Server LocalDB — wersji programu SQL Server Express działającej tylko w systemie Windows.
Rozwiązywanie problemów
Jeśli napotkasz problem, nie możesz go rozwiązać, porównaj kod z ukończonym projektem. Dobrym sposobem uzyskania pomocy jest opublikowanie pytania do StackOverflow.com przy użyciu tagu ASP.NET Core lub taguEF Core.
Przykładowa aplikacja
Aplikacja wbudowana w te samouczki jest podstawową witryną internetową uniwersytetu. Użytkownicy mogą wyświetlać i aktualizować informacje o uczniach, kursach i instruktorach. Poniżej przedstawiono kilka ekranów utworzonych w samouczku.
Styl interfejsu użytkownika tej witryny jest oparty na wbudowanych szablonach projektów. Samouczek koncentruje się na sposobie używania z EF Core platformą ASP.NET Core, a nie na dostosowywaniu interfejsu użytkownika.
Opcjonalnie: skompiluj przykładowy plik do pobrania
To krok jest opcjonalny. Kompilowanie ukończonej aplikacji jest zalecane, gdy masz problemy, których nie można rozwiązać. Jeśli napotkasz problem, nie możesz go rozwiązać, porównaj kod z ukończonym projektem. Pobierz instrukcje.
Wybierz, ContosoUniversity.csproj
aby otworzyć projekt.
Skompiluj projekt.
W konsoli Menedżer pakietów (PMC) uruchom następujące polecenie:
Update-Database
Uruchom projekt, aby zainicjować bazę danych.
Tworzenie projektu aplikacji internetowej
Uruchom program Visual Studio 2022 i wybierz pozycję Utwórz nowy projekt.
W oknie dialogowym Tworzenie nowego projektu wybierz pozycję ASP.NET Core Web App, a następnie wybierz pozycję Dalej.
W oknie dialogowym Konfigurowanie nowego projektu wprowadź wartość
ContosoUniversity
w polu Nazwa projektu. Ważne jest, aby nazwać projekt ContosoUniversity, w tym dopasowanie liter, więc przestrzenie nazw będą zgodne podczas kopiowania i wklejania przykładowego kodu.Wybierz Dalej.
W oknie dialogowym Dodatkowe informacje wybierz pozycję .NET 6.0 (obsługa długoterminowa), a następnie wybierz pozycję Utwórz.
Konfigurowanie stylu witryny
Skopiuj i wklej następujący kod do Pages/Shared/_Layout.cshtml
pliku:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/ContosoUniversity.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2021 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Plik układu ustawia nagłówek, stopkę i menu witryny. Powyższy kod wprowadza następujące zmiany:
- Każde wystąpienie elementu "ContosoUniversity" do "Contoso University". Istnieją trzy wystąpienia.
- Wpisy Home menu i Privacy są usuwane.
- Wpisy są dodawane dla pozycji Informacje, Studenci, Kursy, Instruktorzy i Działy.
W Pages/Index.cshtml
pliku zastąp zawartość pliku następującym kodem:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="row mb-auto">
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 mb-4 ">
<p class="card-text">
Contoso University is a sample application that
demonstrates how to use Entity Framework Core in an
ASP.NET Core Razor Pages web app.
</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column position-static">
<p class="card-text mb-auto">
You can build the application by following the steps in a series of tutorials.
</p>
<p>
@* <a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
*@ </p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column">
<p class="card-text mb-auto">
You can download the completed project from GitHub.
</p>
<p>
@* <a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
*@ </p>
</div>
</div>
</div>
</div>
Powyższy kod zastępuje tekst ASP.NET Core tekstem dotyczącym tej aplikacji.
Uruchom aplikację, aby sprawdzić, czy zostanie wyświetlona home strona.
Model danych
W poniższych sekcjach tworzysz model danych:
Student może zarejestrować się w dowolnej liczbie kursów, a kurs może mieć dowolną liczbę uczniów zarejestrowanych w nim.
Jednostka Student
- Utwórz folder Models w folderze projektu.
- Utwórz
Models/Student.cs
za pomocą następującego kodu: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; } } }
Właściwość ID
staje się kolumną klucza podstawowego tabeli bazy danych, która odpowiada tej klasie. Domyślnie EF Core interpretuje właściwość o nazwie ID
lub classnameID
jako klucz podstawowy. Dlatego alternatywna nazwa automatycznie rozpoznawana dla klucza podstawowego Student
klasy to StudentID
. Aby uzyskać więcej informacji, zobacz EF Core — Klucze.
Właściwość Enrollments
jest właściwością nawigacji. Właściwości nawigacji przechowują inne jednostki powiązane z tą jednostką. W takim przypadku Enrollments
właściwość Student
jednostki przechowuje wszystkie Enrollment
jednostki powiązane z tym uczniem. Jeśli na przykład wiersz Student w bazie danych zawiera dwa powiązane wiersze rejestracji, Enrollments
właściwość nawigacji zawiera te dwie jednostki rejestracji.
W bazie danych wiersz rejestracji jest powiązany z wierszem Student, jeśli jego StudentID
kolumna zawiera wartość identyfikatora ucznia. Załóżmy na przykład, że wiersz Student ma identyfikator =1. Powiązane wiersze rejestracji będą miały StudentID
wartość = 1. StudentID
jest kluczem obcym w tabeli Rejestracja.
Właściwość jest zdefiniowana Enrollments
jako ICollection<Enrollment>
, ponieważ może istnieć wiele powiązanych jednostek rejestracji. Można użyć innych typów kolekcji, takich jak List<Enrollment>
lub HashSet<Enrollment>
. Gdy ICollection<Enrollment>
jest używany, EF Core domyślnie tworzy HashSet<Enrollment>
kolekcję.
Jednostka Rejestracja
Utwórz Models/Enrollment.cs
za pomocą następującego kodu:
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.Models
{
public enum Grade
{
A, B, C, D, F
}
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
[DisplayFormat(NullDisplayText = "No grade")]
public Grade? Grade { get; set; }
public Course Course { get; set; }
public Student Student { get; set; }
}
}
Właściwość jest kluczem podstawowym. Ta EnrollmentID
jednostka używa classnameID
wzorca zamiast ID
samego siebie. W przypadku modelu danych produkcyjnych wielu deweloperów wybiera jeden wzorzec i konsekwentnie go używa. W tym samouczku użyto obu tych elementów, aby zilustrować, że obie te elementy działają. Użycie ID
bez classname
ułatwia implementowanie niektórych rodzajów zmian modelu danych.
Właściwość Grade
to enum
. Znak zapytania po Grade
deklaracji typu wskazuje, że Grade
właściwość jest dopuszczana do wartości null. Ocena o wartości null różni się od klasy zerowej — wartość null oznacza, że ocena nie jest znana lub nie została jeszcze przypisana.
Właściwość StudentID
jest kluczem obcym, a odpowiadająca mu właściwość nawigacji to Student
. Jednostka Enrollment
jest skojarzona z jedną Student
jednostką, więc właściwość zawiera jedną Student
jednostkę.
Właściwość CourseID
jest kluczem obcym, a odpowiadająca mu właściwość nawigacji to Course
. Jednostka Enrollment
jest skojarzona z jedną jednostką Course
.
EF Core interpretuje właściwość jako klucz obcy, jeśli ma nazwę <navigation property name><primary key property name>
. Na przykładStudentID
jest kluczem obcym Student
właściwości nawigacji, ponieważ Student
kluczem podstawowym jednostki jest ID
. Właściwości klucza obcego mogą również mieć nazwę <primary key property name>
. Na przykład ponieważ CourseID
Course
kluczem podstawowym jednostki jest CourseID
.
Jednostka Course
Utwórz Models/Course.cs
za pomocą następującego kodu:
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; }
}
}
Właściwość Enrollments
jest właściwością nawigacji. Jednostka Course
może być powiązana z dowolną Enrollment
liczbą jednostek.
Atrybut DatabaseGenerated
umożliwia aplikacji określenie klucza podstawowego zamiast generowania jej przez bazę danych.
Kompilowanie aplikacji. Kompilator generuje kilka ostrzeżeń dotyczących sposobu null
obsługi wartości. Aby uzyskać więcej informacji, zobacz ten problem z usługą GitHub, typy referencyjne dopuszczane do wartości Null i Samouczek: Wyrażanie intencji projektowej przy użyciu typów odwołań dopuszczanych do wartości null i innych niż null.
Aby wyeliminować ostrzeżenia z typów odwołań dopuszczanych do wartości null, usuń następujący wiersz z ContosoUniversity.csproj
pliku:
<Nullable>enable</Nullable>
Aparat tworzenia szkieletów obecnie nie obsługuje typów odwołań dopuszczających wartość null, dlatego modele używane w szkieletach nie mogą też być obsługiwane.
Usuń adnotację ?
typu odwołania dopuszczanego z wartości null, Pages/Error.cshtml.cs
public string? RequestId { get; set; }
aby kompilować projekt bez ostrzeżeń kompilatora.
Strony ucznia szkieletu
W tej sekcji narzędzie do tworzenia szkieletów ASP.NET Core służy do generowania:
- Klasa EF Core
DbContext
. Kontekst jest główną klasą, która koordynuje funkcje programu Entity Framework dla danego modelu danych. Pochodzi z Microsoft.EntityFrameworkCore.DbContext klasy . - Razor strony obsługujące operacje Create, Read, Update i Delete (CRUD) dla
Student
jednostki.
- Utwórz folder Pages/Students.
- W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Pages/Students i wybierz polecenie Dodaj>nowy element szkieletowy.
- W oknie dialogowym Dodawanie nowego elementu szkieletu:
- Na lewej karcie wybierz pozycję Zainstalowane > wspólne >Razor strony
- Wybierz pozycję Strony przy użyciu programu Entity Framework (CRUD)>ADD.Razor
- W oknie dialogowym Dodawanie Razor stron przy użyciu programu Entity Framework (CRUD):
- Z listy rozwijanej Klasa modelu wybierz pozycję Student (ContosoUniversity.Models).
- W wierszu Klasy kontekstu danych wybierz + znak (plus).
- Zmień nazwę kontekstu danych tak, aby zakończyła
SchoolContext
się zamiastContosoUniversityContext
. Zaktualizowana nazwa kontekstu:ContosoUniversity.Data.SchoolContext
- Wybierz pozycję Dodaj , aby zakończyć dodawanie klasy kontekstu danych.
- Wybierz pozycję Dodaj , aby zakończyć okno dialogowe Dodawanie Razor stron .
- Zmień nazwę kontekstu danych tak, aby zakończyła
Następujące pakiety są instalowane automatycznie:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
Microsoft.VisualStudio.Web.CodeGeneration.Design
Jeśli poprzedni krok zakończy się niepowodzeniem, skompiluj projekt i spróbuj ponownie wykonać krok szkieletu.
Proces tworzenia szkieletów:
- Tworzy Razor strony w folderze Pages/Students :
Create.cshtml
iCreate.cshtml.cs
Delete.cshtml
iDelete.cshtml.cs
Details.cshtml
iDetails.cshtml.cs
Edit.cshtml
iEdit.cshtml.cs
Index.cshtml
iIndex.cshtml.cs
- Tworzy
Data/SchoolContext.cs
polecenie . - Dodaje kontekst do wstrzykiwania zależności w pliku
Program.cs
. - Dodaje parametry połączenia bazy danych do elementu
appsettings.json
.
Parametry połączenia bazy danych
Narzędzie do tworzenia szkieletów generuje parametry połączenia w appsettings.json
pliku.
Parametry połączenia określa sql Server LocalDB:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=SchoolContext-0e9;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
LocalDB to uproszczona wersja aparatu bazy danych SQL Server Express i jest przeznaczona do tworzenia aplikacji, a nie do użytku produkcyjnego. Domyślnie baza danych LocalDB tworzy pliki .mdf w C:/Users/<user>
katalogu.
Aktualizowanie klasy kontekstu bazy danych
Główną klasą, która koordynuje EF Core funkcjonalność danego modelu danych, jest klasa kontekstu bazy danych. Kontekst pochodzi z elementu Microsoft.EntityFrameworkCore.DbContext. Kontekst określa, które jednostki są uwzględnione w modelu danych. W tym projekcie klasa nosi nazwę SchoolContext
.
Zaktualizuj Data/SchoolContext.cs
za pomocą następującego kodu:
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext (DbContextOptions<SchoolContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
Powyższy kod zmienia się z liczby pojedynczej na liczbę mnogą DbSet<Student> Student
DbSet<Student> Students
. Aby kod Razor Pages był zgodny z nową DBSet
nazwą, wprowadź globalną zmianę z: _context.Student.
do: _context.Students.
Istnieje 8 wystąpień.
Ponieważ zestaw jednostek zawiera wiele jednostek, wielu deweloperów preferuje DBSet
nazwy właściwości powinny być mnogią.
Wyróżniony kod:
- Tworzy DbSet<TEntity> właściwość dla każdego zestawu jednostek. Terminologia EF Core :
- Zestaw jednostek zwykle odpowiada tabeli bazy danych.
- Jednostka odpowiada wierszowi w tabeli.
- Wywołuje OnModelCreating.
OnModelCreating
:- Jest wywoływany, gdy
SchoolContext
został zainicjowany, ale przed zabezpieczeniem modelu i użytym do zainicjowania kontekstu. - Jest to wymagane, ponieważ w dalszej części samouczka
Student
jednostka będzie zawierać odwołania do innych jednostek.
- Jest wywoływany, gdy
Mamy nadzieję rozwiązać ten problem w przyszłej wersji.
Program.cs
ASP.NET Core jest kompilowany za pomocą wstrzykiwania zależności. Usługi, takie jak te SchoolContext
, są rejestrowane za pomocą wstrzykiwania zależności podczas uruchamiania aplikacji. Składniki, które wymagają tych usług, takich jak Razor Pages, są udostępniane za pomocą parametrów konstruktora. Kod konstruktora, który pobiera wystąpienie kontekstu bazy danych, jest wyświetlany w dalszej części samouczka.
Narzędzie do tworzenia szkieletów automatycznie zarejestrowało klasę kontekstu za pomocą kontenera wstrzykiwania zależności.
Następujące wyróżnione wiersze zostały dodane przez szkielet:
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext")));
Nazwa parametry połączenia jest przekazywana do kontekstu przez wywołanie metody w DbContextOptions obiekcie. W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje parametry połączenia z appsettings.json
pliku lub appsettings.Development.json
.
Dodawanie filtru wyjątku bazy danych
Dodaj AddDatabaseDeveloperPageExceptionFilter element i UseMigrationsEndPoint , jak pokazano w poniższym kodzie:
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext")));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
else
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
Dodaj pakiet NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.
W konsoli Menedżer pakietów wprowadź następujące polecenie, aby dodać pakiet NuGet:
Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Pakiet NuGet udostępnia oprogramowanie pośredniczące ASP.NET Core dla stron błędów programu Entity Framework Core. To oprogramowanie pośredniczące pomaga wykrywać i diagnozować błędy migracji programu Entity Framework Core.
Zawiera AddDatabaseDeveloperPageExceptionFilter
przydatne informacje o błędach w środowisku projektowym pod kątem błędów migracji ef.
Tworzenie bazy danych
Zaktualizuj Program.cs
bazę danych, aby utworzyć ją, jeśli nie istnieje:
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext")));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
else
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
// DbInitializer.Initialize(context);
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Metoda EnsureCreated nie podejmuje żadnej akcji, jeśli istnieje baza danych kontekstu. Jeśli baza danych nie istnieje, tworzy bazę danych i schemat. EnsureCreated
włącza następujący przepływ pracy do obsługi zmian modelu danych:
- Usuń bazę danych. Wszystkie istniejące dane zostaną utracone.
- Zmień model danych. Na przykład dodaj
EmailAddress
pole. - Uruchom aplikację.
EnsureCreated
tworzy bazę danych przy użyciu nowego schematu.
Ten przepływ pracy działa na wczesnym etapie opracowywania, gdy schemat jest szybko ewoluujący, o ile dane nie muszą być zachowywane. Sytuacja jest inna, gdy należy zachować dane wprowadzone w bazie danych. W takim przypadku należy użyć migracji.
W dalszej części serii samouczków baza danych zostanie usunięta, która została utworzona przez EnsureCreated
program i zostanie użyta migracja. Nie można zaktualizować bazy danych utworzonej przez EnsureCreated
program przy użyciu migracji.
Testowanie aplikacji
- Uruchom aplikację.
- Wybierz link Uczniowie, a następnie pozycję Utwórz nowy.
- Przetestuj linki Edytuj, Szczegóły i Usuń.
Inicjowanie bazy danych
Metoda EnsureCreated
tworzy pustą bazę danych. Ta sekcja dodaje kod, który wypełnia bazę danych danymi testowymi.
Utwórz Data/DbInitializer.cs
za pomocą następującego kodu:
using ContosoUniversity.Models;
namespace ContosoUniversity.Data
{
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
// Look for any students.
if (context.Students.Any())
{
return; // DB has been seeded
}
var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
};
context.Students.AddRange(students);
context.SaveChanges();
var courses = new Course[]
{
new Course{CourseID=1050,Title="Chemistry",Credits=3},
new Course{CourseID=4022,Title="Microeconomics",Credits=3},
new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
new Course{CourseID=1045,Title="Calculus",Credits=4},
new Course{CourseID=3141,Title="Trigonometry",Credits=4},
new Course{CourseID=2021,Title="Composition",Credits=3},
new Course{CourseID=2042,Title="Literature",Credits=4}
};
context.Courses.AddRange(courses);
context.SaveChanges();
var enrollments = new Enrollment[]
{
new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
new Enrollment{StudentID=3,CourseID=1050},
new Enrollment{StudentID=4,CourseID=1050},
new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
new Enrollment{StudentID=6,CourseID=1045},
new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
};
context.Enrollments.AddRange(enrollments);
context.SaveChanges();
}
}
}
Kod sprawdza, czy w bazie danych znajdują się uczniowie. Jeśli nie ma uczniów, dodaje dane testowe do bazy danych. Tworzy dane testowe w tablicach, a nie List<T>
kolekcje w celu zoptymalizowania wydajności.
- W
Program.cs
plikuDbInitializer.Initialize
usuń//
z wiersza:
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
DbInitializer.Initialize(context);
}
Zatrzymaj aplikację, jeśli jest uruchomiona, i uruchom następujące polecenie w konsoli Menedżer pakietów (PMC):
Drop-Database -Confirm
Odpowiedz,
Y
aby usunąć bazę danych.
- Ponownie uruchom aplikację.
- Wybierz stronę Uczniowie, aby wyświetlić dane rozstawione.
Wyświetlanie bazy danych
- Otwórz program SQL Server Eksplorator obiektów (SSOX) z menu Widok w programie Visual Studio.
- W programie SSOX wybierz pozycję (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Nazwa bazy danych jest generowana na podstawie podanej wcześniej nazwy kontekstu oraz kreski i identyfikatora GUID.
- Rozwiń węzeł Tabele.
- Kliknij prawym przyciskiem myszy tabelę Student i kliknij pozycję Wyświetl dane , aby wyświetlić utworzone kolumny i wiersze wstawione do tabeli.
- Kliknij prawym przyciskiem myszy tabelę Student i kliknij pozycję Wyświetl kod , aby zobaczyć, jak
Student
model jest mapowy naStudent
schemat tabeli.
Asynchroniczne metody EF w aplikacjach internetowych platformy ASP.NET Core
Programowanie asynchroniczne jest trybem domyślnym dla ASP.NET Core i EF Core.
Serwer internetowy ma ograniczoną liczbę dostępnych wątków, a w sytuacjach dużego obciążenia wszystkie dostępne wątki mogą być używane. W takim przypadku serwer nie może przetworzyć nowych żądań, dopóki wątki nie zostaną zwolnione. W przypadku kodu synchronicznego wiele wątków może być powiązanych, gdy nie działają, ponieważ oczekują na zakończenie operacji we/wy. W przypadku kodu asynchronicznego, gdy proces oczekuje na ukończenie operacji we/wy, jego wątek zostanie zwolniony do użycia przez serwer do przetwarzania innych żądań. W rezultacie kod asynchroniczny umożliwia wydajniejsze wykorzystanie zasobów serwera, a serwer może obsługiwać więcej ruchu bez opóźnień.
Kod asynchroniczny wprowadza niewielką ilość obciążeń w czasie wykonywania. W przypadku sytuacji o niskim natężeniu ruchu wydajność jest niewielka, podczas gdy w przypadku dużych sytuacji drogowych potencjalna poprawa wydajności jest znacząca.
W poniższym kodzie asynchroniczne słowo kluczowe, wartość zwracana, Task
await
słowo kluczowe i ToListAsync
metoda sprawiają, że kod jest wykonywany asynchronicznie.
public async Task OnGetAsync()
{
Students = await _context.Students.ToListAsync();
}
- Słowo
async
kluczowe nakazuje kompilatorowi:- Generowanie wywołań zwrotnych dla części treści metody.
- Utwórz zwrócony obiekt Task.
- Typ zwracany reprezentuje bieżącą
Task
pracę. - Słowo
await
kluczowe powoduje, że kompilator dzieli metodę na dwie części. Pierwsza część kończy się operacją, która została uruchomiona asynchronicznie. Druga część jest umieszczana w metodzie wywołania zwrotnego wywoływanej po zakończeniu operacji. ToListAsync
to asynchroniczna wersjaToList
metody rozszerzenia.
Niektóre kwestie, o których należy pamiętać podczas pisania kodu asynchronicznego, który używa EF Coremetody :
- Tylko instrukcje, które powodują wysyłanie zapytań lub poleceń do bazy danych, są wykonywane asynchronicznie.
ToListAsync
Obejmuje to , ,FirstOrDefaultAsync
SingleOrDefaultAsync
iSaveChangesAsync
. Nie zawiera instrukcji, które po prostu zmieniają elementIQueryable
, na przykładvar students = context.Students.Where(s => s.LastName == "Davolio")
. - Kontekst EF Core nie jest bezpieczny wątkiem: nie próbuj wykonywać wielu operacji równolegle.
- Aby skorzystać z zalet wydajności kodu asynchronicznego, sprawdź, czy pakiety bibliotek (takie jak stronicowanie) używają asynchronicznego, jeśli wywołają EF Core metody wysyłające zapytania do bazy danych.
Aby uzyskać więcej informacji na temat programowania asynchronicznego na platformie .NET, zobacz Async Overview and Asynchronous programming with async and await (Omówienie asynchroniczne i asynchroniczne programowanie asynchroniczne za pomocą asynchronicznego i oczekiwania).
Ostrzeżenie
Implementacja asynchronicznego elementu Microsoft.Data.SqlClient ma znane problemy (#593, #601 i inne). Jeśli występują nieoczekiwane problemy z wydajnością, spróbuj zamiast tego użyć polecenia synchronizacji, szczególnie w przypadku obsługi dużych wartości tekstowych lub binarnych.
Zagadnienia dotyczące wydajności
Ogólnie rzecz biorąc, strona internetowa nie powinna ładować dowolnej liczby wierszy. Zapytanie powinno używać stronicowania lub podejścia ograniczającego. Na przykład powyższe zapytanie może użyć Take
polecenia , aby ograniczyć zwracane wiersze:
public async Task OnGetAsync()
{
Student = await _context.Students.Take(10).ToListAsync();
}
Wyliczanie dużej tabeli w widoku może zwrócić częściowo skonstruowaną odpowiedź HTTP 200, jeśli wyjątek bazy danych występuje w części przez wyliczenie.
Stronicowanie zostało omówione w dalszej części samouczka.
Aby uzyskać więcej informacji, zobacz Zagadnienia dotyczące wydajności (EF).
Następne kroki
Używanie narzędzia SQLite do programowania, programu SQL Server dla środowiska produkcyjnego
Jest to pierwszy z serii samouczków, które pokazują, jak używać programu Entity Framework (EF) Core w aplikacji ASP.NET Core Razor Pages . Samouczki tworzą witrynę internetową fikcyjnego uniwersytetu Contoso. Witryna zawiera funkcje, takie jak wstęp dla uczniów, tworzenie kursów i zadania instruktora. W tym samouczku jest używane pierwsze podejście do kodu. Aby uzyskać informacje na temat korzystania z tego samouczka przy użyciu pierwszego podejścia do bazy danych, zobacz ten problem z usługą GitHub.
Pobierz lub wyświetl ukończoną aplikację. Pobierz instrukcje.
Wymagania wstępne
- Jeśli dopiero zaczynasz Razor pracę ze stronami, zapoznaj się z serią samouczków Wprowadzenie do Razor stron przed rozpoczęciem tego samouczka.
- Program Visual Studio 2019 16.8 lub nowsza wersja z pakietem roboczym tworzenia aplikacji ASP.NET. i aplikacji internetowych
- Zestaw .NET SDK 5.0
Aparaty bazy danych
Instrukcje programu Visual Studio używają programu SQL Server LocalDB — wersji programu SQL Server Express działającej tylko w systemie Windows.
Rozwiązywanie problemów
Jeśli napotkasz problem, nie możesz go rozwiązać, porównaj kod z ukończonym projektem. Dobrym sposobem uzyskania pomocy jest opublikowanie pytania do StackOverflow.com przy użyciu tagu ASP.NET Core lub taguEF Core.
Przykładowa aplikacja
Aplikacja wbudowana w te samouczki jest podstawową witryną internetową uniwersytetu. Użytkownicy mogą wyświetlać i aktualizować informacje o uczniach, kursach i instruktorach. Poniżej przedstawiono kilka ekranów utworzonych w samouczku.
Styl interfejsu użytkownika tej witryny jest oparty na wbudowanych szablonach projektów. Samouczek koncentruje się na sposobie używania z EF Core platformą ASP.NET Core, a nie na dostosowywaniu interfejsu użytkownika.
Opcjonalnie: skompiluj przykładowy plik do pobrania
To krok jest opcjonalny. Kompilowanie ukończonej aplikacji jest zalecane, gdy masz problemy, których nie można rozwiązać. Jeśli napotkasz problem, nie możesz go rozwiązać, porównaj kod z ukończonym projektem. Pobierz instrukcje.
Wybierz, ContosoUniversity.csproj
aby otworzyć projekt.
- Skompiluj projekt.
- W konsoli Menedżer pakietów (PMC) uruchom następujące polecenie:
Update-Database
Uruchom projekt, aby zainicjować bazę danych.
Tworzenie projektu aplikacji internetowej
- Uruchom program Visual Studio i wybierz pozycję Utwórz nowy projekt.
- W oknie dialogowym Tworzenie nowego projektu wybierz pozycję ASP.NET Core Web Application>Next (Dalej).
- W oknie dialogowym Konfigurowanie nowego projektu wprowadź wartość
ContosoUniversity
w polu Nazwa projektu. Należy użyć tej dokładnej nazwy, w tym wielkich liter, więc każdynamespace
z nich jest zgodny podczas kopiowania kodu. - Wybierz pozycję Utwórz.
- W oknie dialogowym Tworzenie nowej aplikacji internetowej platformy ASP.NET Core wybierz pozycję:
- Platforma .NET Core i ASP.NET Core 5.0 na listach rozwijanych.
- ASP.NET Core Web App.
- Utwórz
Konfigurowanie stylu witryny
Skopiuj i wklej następujący kod do Pages/Shared/_Layout.cshtml
pliku:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2021 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
Plik układu ustawia nagłówek, stopkę i menu witryny. Powyższy kod wprowadza następujące zmiany:
- Każde wystąpienie elementu "ContosoUniversity" do "Contoso University". Istnieją trzy wystąpienia.
- Wpisy Home menu i Privacy są usuwane.
- Wpisy są dodawane dla pozycji Informacje, Studenci, Kursy, Instruktorzy i Działy.
W Pages/Index.cshtml
pliku zastąp zawartość pliku następującym kodem:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="row mb-auto">
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 mb-4 ">
<p class="card-text">
Contoso University is a sample application that
demonstrates how to use Entity Framework Core in an
ASP.NET Core Razor Pages web app.
</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column position-static">
<p class="card-text mb-auto">
You can build the application by following the steps in a series of tutorials.
</p>
<p>
<a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column">
<p class="card-text mb-auto">
You can download the completed project from GitHub.
</p>
<p>
<a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
</p>
</div>
</div>
</div>
</div>
Powyższy kod zastępuje tekst ASP.NET Core tekstem dotyczącym tej aplikacji.
Uruchom aplikację, aby sprawdzić, czy zostanie wyświetlona home strona.
Model danych
W poniższych sekcjach tworzysz model danych:
Student może zarejestrować się w dowolnej liczbie kursów, a kurs może mieć dowolną liczbę uczniów zarejestrowanych w nim.
Jednostka Student
Utwórz folder Models w folderze projektu.
Utwórz
Models/Student.cs
za pomocą następującego kodu: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; } } }
Właściwość ID
staje się kolumną klucza podstawowego tabeli bazy danych, która odpowiada tej klasie. Domyślnie EF Core interpretuje właściwość o nazwie ID
lub classnameID
jako klucz podstawowy. Dlatego alternatywna nazwa automatycznie rozpoznawana dla klucza podstawowego Student
klasy to StudentID
. Aby uzyskać więcej informacji, zobacz EF Core — Klucze.
Właściwość Enrollments
jest właściwością nawigacji. Właściwości nawigacji przechowują inne jednostki powiązane z tą jednostką. W takim przypadku Enrollments
właściwość Student
jednostki przechowuje wszystkie Enrollment
jednostki powiązane z tym uczniem. Jeśli na przykład wiersz Student w bazie danych zawiera dwa powiązane wiersze rejestracji, Enrollments
właściwość nawigacji zawiera te dwie jednostki rejestracji.
W bazie danych wiersz rejestracji jest powiązany z wierszem Student, jeśli jego StudentID
kolumna zawiera wartość identyfikatora ucznia. Załóżmy na przykład, że wiersz Student ma identyfikator =1. Powiązane wiersze rejestracji będą miały StudentID
wartość = 1. StudentID
jest kluczem obcym w tabeli Rejestracja.
Właściwość jest zdefiniowana Enrollments
jako ICollection<Enrollment>
, ponieważ może istnieć wiele powiązanych jednostek rejestracji. Można użyć innych typów kolekcji, takich jak List<Enrollment>
lub HashSet<Enrollment>
. Gdy ICollection<Enrollment>
jest używany, EF Core domyślnie tworzy HashSet<Enrollment>
kolekcję.
Jednostka Rejestracja
Utwórz Models/Enrollment.cs
za pomocą następującego kodu:
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.Models
{
public enum Grade
{
A, B, C, D, F
}
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
[DisplayFormat(NullDisplayText = "No grade")]
public Grade? Grade { get; set; }
public Course Course { get; set; }
public Student Student { get; set; }
}
}
Właściwość jest kluczem podstawowym. Ta EnrollmentID
jednostka używa classnameID
wzorca zamiast ID
samego siebie. W przypadku modelu danych produkcyjnych wielu deweloperów wybiera jeden wzorzec i konsekwentnie go używa. W tym samouczku użyto obu tych elementów, aby zilustrować, że obie te elementy działają. Użycie ID
bez classname
ułatwia implementowanie niektórych rodzajów zmian modelu danych.
Właściwość Grade
to enum
. Znak zapytania po Grade
deklaracji typu wskazuje, że Grade
właściwość jest dopuszczana do wartości null. Ocena o wartości null różni się od klasy zerowej — wartość null oznacza, że ocena nie jest znana lub nie została jeszcze przypisana.
Właściwość StudentID
jest kluczem obcym, a odpowiadająca mu właściwość nawigacji to Student
. Jednostka Enrollment
jest skojarzona z jedną Student
jednostką, więc właściwość zawiera jedną Student
jednostkę.
Właściwość CourseID
jest kluczem obcym, a odpowiadająca mu właściwość nawigacji to Course
. Jednostka Enrollment
jest skojarzona z jedną jednostką Course
.
EF Core interpretuje właściwość jako klucz obcy, jeśli ma nazwę <navigation property name><primary key property name>
. Na przykładStudentID
jest kluczem obcym Student
właściwości nawigacji, ponieważ Student
kluczem podstawowym jednostki jest ID
. Właściwości klucza obcego mogą również mieć nazwę <primary key property name>
. Na przykład ponieważ CourseID
Course
kluczem podstawowym jednostki jest CourseID
.
Jednostka Course
Utwórz Models/Course.cs
za pomocą następującego kodu:
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; }
}
}
Właściwość Enrollments
jest właściwością nawigacji. Jednostka Course
może być powiązana z dowolną Enrollment
liczbą jednostek.
Atrybut DatabaseGenerated
umożliwia aplikacji określenie klucza podstawowego zamiast generowania jej przez bazę danych.
Skompiluj projekt, aby sprawdzić, czy nie ma żadnych błędów kompilatora.
Strony ucznia szkieletu
W tej sekcji narzędzie do tworzenia szkieletów ASP.NET Core służy do generowania:
- Klasa EF Core
DbContext
. Kontekst jest główną klasą, która koordynuje funkcje programu Entity Framework dla danego modelu danych. Pochodzi z Microsoft.EntityFrameworkCore.DbContext klasy . - Razor strony obsługujące operacje Create, Read, Update i Delete (CRUD) dla
Student
jednostki.
- Utwórz folder Pages/Students.
- W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Pages/Students i wybierz polecenie Dodaj>nowy element szkieletowy.
- W oknie dialogowym Dodawanie nowego elementu szkieletu:
- Na lewej karcie wybierz pozycję Zainstalowane > wspólne >Razor strony
- Wybierz pozycję Strony przy użyciu programu Entity Framework (CRUD)>ADD.Razor
- W oknie dialogowym Dodawanie Razor stron przy użyciu programu Entity Framework (CRUD):
- Z listy rozwijanej Klasa modelu wybierz pozycję Student (ContosoUniversity.Models).
- W wierszu Klasy kontekstu danych wybierz + znak (plus).
- Zmień nazwę kontekstu danych tak, aby zakończyła
SchoolContext
się zamiastContosoUniversityContext
. Zaktualizowana nazwa kontekstu:ContosoUniversity.Data.SchoolContext
- Wybierz pozycję Dodaj , aby zakończyć dodawanie klasy kontekstu danych.
- Wybierz pozycję Dodaj , aby zakończyć okno dialogowe Dodawanie Razor stron .
- Zmień nazwę kontekstu danych tak, aby zakończyła
Jeśli tworzenie szkieletu zakończy się niepowodzeniem z powodu błędu 'Install the package Microsoft.VisualStudio.Web.CodeGeneration.Design and try again.'
, uruchom ponownie narzędzie szkieletu lub zobacz ten problem z usługą GitHub.
Następujące pakiety są instalowane automatycznie:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
Microsoft.VisualStudio.Web.CodeGeneration.Design
Jeśli poprzedni krok zakończy się niepowodzeniem, skompiluj projekt i spróbuj ponownie wykonać krok szkieletu.
Proces tworzenia szkieletów:
- Tworzy Razor strony w folderze Pages/Students :
Create.cshtml
iCreate.cshtml.cs
Delete.cshtml
iDelete.cshtml.cs
Details.cshtml
iDetails.cshtml.cs
Edit.cshtml
iEdit.cshtml.cs
Index.cshtml
iIndex.cshtml.cs
- Tworzy
Data/SchoolContext.cs
polecenie . - Dodaje kontekst do wstrzykiwania zależności w pliku
Startup.cs
. - Dodaje parametry połączenia bazy danych do elementu
appsettings.json
.
Parametry połączenia bazy danych
Narzędzie do tworzenia szkieletów generuje parametry połączenia w appsettings.json
pliku.
Parametry połączenia określa sql Server LocalDB:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=CU-1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
LocalDB to uproszczona wersja aparatu bazy danych SQL Server Express i jest przeznaczona do tworzenia aplikacji, a nie do użytku produkcyjnego. Domyślnie baza danych LocalDB tworzy pliki .mdf w C:/Users/<user>
katalogu.
Aktualizowanie klasy kontekstu bazy danych
Główną klasą, która koordynuje EF Core funkcjonalność danego modelu danych, jest klasa kontekstu bazy danych. Kontekst pochodzi z elementu Microsoft.EntityFrameworkCore.DbContext. Kontekst określa, które jednostki są uwzględnione w modelu danych. W tym projekcie klasa nosi nazwę SchoolContext
.
Zaktualizuj Data/SchoolContext.cs
za pomocą następującego kodu:
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext (DbContextOptions<SchoolContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
Powyższy kod zmienia się z liczby pojedynczej na liczbę mnogą DbSet<Student> Student
DbSet<Student> Students
. Aby kod Razor Pages był zgodny z nową DBSet
nazwą, wprowadź globalną zmianę z: _context.Student.
do: _context.Students.
Istnieje 8 wystąpień.
Ponieważ zestaw jednostek zawiera wiele jednostek, wielu deweloperów preferuje DBSet
nazwy właściwości powinny być mnogią.
Wyróżniony kod:
- Tworzy DbSet<TEntity> właściwość dla każdego zestawu jednostek. Terminologia EF Core :
- Zestaw jednostek zwykle odpowiada tabeli bazy danych.
- Jednostka odpowiada wierszowi w tabeli.
- Wywołuje OnModelCreating.
OnModelCreating
:- Jest wywoływany, gdy
SchoolContext
został zainicjowany, ale przed zabezpieczeniem modelu i użytym do zainicjowania kontekstu. - Jest to wymagane, ponieważ w dalszej części samouczka
Student
jednostka będzie zawierać odwołania do innych jednostek.
- Jest wywoływany, gdy
Skompiluj projekt, aby sprawdzić, czy nie ma żadnych błędów kompilatora.
Startup.cs
ASP.NET Core jest kompilowany za pomocą wstrzykiwania zależności. Usługi, takie jak te SchoolContext
, są rejestrowane za pomocą wstrzykiwania zależności podczas uruchamiania aplikacji. Składniki, które wymagają tych usług, takich jak Razor Pages, są udostępniane za pomocą parametrów konstruktora. Kod konstruktora, który pobiera wystąpienie kontekstu bazy danych, jest wyświetlany w dalszej części samouczka.
Narzędzie do tworzenia szkieletów automatycznie zarejestrowało klasę kontekstu za pomocą kontenera wstrzykiwania zależności.
Następujące wyróżnione wiersze zostały dodane przez szkielet:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
}
Nazwa parametry połączenia jest przekazywana do kontekstu przez wywołanie metody w DbContextOptions obiekcie. W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje parametry połączenia z appsettings.json
pliku.
Dodawanie filtru wyjątku bazy danych
Dodaj AddDatabaseDeveloperPageExceptionFilter element i UseMigrationsEndPoint , jak pokazano w poniższym kodzie:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
services.AddDatabaseDeveloperPageExceptionFilter();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Dodaj pakiet NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.
W konsoli Menedżer pakietów wprowadź następujące polecenie, aby dodać pakiet NuGet:
Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
Pakiet NuGet udostępnia oprogramowanie pośredniczące ASP.NET Core dla stron błędów programu Entity Framework Core. To oprogramowanie pośredniczące pomaga wykrywać i diagnozować błędy migracji programu Entity Framework Core.
Zawiera AddDatabaseDeveloperPageExceptionFilter
przydatne informacje o błędach w środowisku projektowym pod kątem błędów migracji ef.
Tworzenie bazy danych
Zaktualizuj Program.cs
bazę danych, aby utworzyć ją, jeśli nie istnieje:
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
namespace ContosoUniversity
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
CreateDbIfNotExists(host);
host.Run();
}
private static void CreateDbIfNotExists(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
// DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred creating the DB.");
}
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Metoda EnsureCreated nie podejmuje żadnej akcji, jeśli istnieje baza danych kontekstu. Jeśli baza danych nie istnieje, tworzy bazę danych i schemat. EnsureCreated
włącza następujący przepływ pracy do obsługi zmian modelu danych:
- Usuń bazę danych. Wszystkie istniejące dane zostaną utracone.
- Zmień model danych. Na przykład dodaj
EmailAddress
pole. - Uruchom aplikację.
EnsureCreated
tworzy bazę danych przy użyciu nowego schematu.
Ten przepływ pracy działa na wczesnym etapie opracowywania, gdy schemat jest szybko ewoluujący, o ile dane nie muszą być zachowywane. Sytuacja jest inna, gdy należy zachować dane wprowadzone w bazie danych. W takim przypadku należy użyć migracji.
W dalszej części serii samouczków baza danych zostanie usunięta, która została utworzona przez EnsureCreated
program i zostanie użyta migracja. Nie można zaktualizować bazy danych utworzonej przez EnsureCreated
program przy użyciu migracji.
Testowanie aplikacji
- Uruchom aplikację.
- Wybierz link Uczniowie, a następnie pozycję Utwórz nowy.
- Przetestuj linki Edytuj, Szczegóły i Usuń.
Inicjowanie bazy danych
Metoda EnsureCreated
tworzy pustą bazę danych. Ta sekcja dodaje kod, który wypełnia bazę danych danymi testowymi.
Utwórz Data/DbInitializer.cs
za pomocą następującego kodu:
using ContosoUniversity.Models;
using System;
using System.Linq;
namespace ContosoUniversity.Data
{
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
// Look for any students.
if (context.Students.Any())
{
return; // DB has been seeded
}
var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
};
context.Students.AddRange(students);
context.SaveChanges();
var courses = new Course[]
{
new Course{CourseID=1050,Title="Chemistry",Credits=3},
new Course{CourseID=4022,Title="Microeconomics",Credits=3},
new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
new Course{CourseID=1045,Title="Calculus",Credits=4},
new Course{CourseID=3141,Title="Trigonometry",Credits=4},
new Course{CourseID=2021,Title="Composition",Credits=3},
new Course{CourseID=2042,Title="Literature",Credits=4}
};
context.Courses.AddRange(courses);
context.SaveChanges();
var enrollments = new Enrollment[]
{
new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
new Enrollment{StudentID=3,CourseID=1050},
new Enrollment{StudentID=4,CourseID=1050},
new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
new Enrollment{StudentID=6,CourseID=1045},
new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
};
context.Enrollments.AddRange(enrollments);
context.SaveChanges();
}
}
}
Kod sprawdza, czy w bazie danych znajdują się uczniowie. Jeśli nie ma uczniów, dodaje dane testowe do bazy danych. Tworzy dane testowe w tablicach, a nie List<T>
kolekcje w celu zoptymalizowania wydajności.
W
Program.cs
plikuDbInitializer.Initialize
usuń//
z wiersza:context.Database.EnsureCreated(); DbInitializer.Initialize(context);
Zatrzymaj aplikację, jeśli jest uruchomiona, i uruchom następujące polecenie w konsoli Menedżer pakietów (PMC):
Drop-Database -Confirm
Odpowiedz,
Y
aby usunąć bazę danych.
- Ponownie uruchom aplikację.
- Wybierz stronę Uczniowie, aby wyświetlić dane rozstawione.
Wyświetlanie bazy danych
- Otwórz program SQL Server Eksplorator obiektów (SSOX) z menu Widok w programie Visual Studio.
- W programie SSOX wybierz pozycję (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Nazwa bazy danych jest generowana na podstawie podanej wcześniej nazwy kontekstu oraz kreski i identyfikatora GUID.
- Rozwiń węzeł Tabele.
- Kliknij prawym przyciskiem myszy tabelę Student i kliknij pozycję Wyświetl dane , aby wyświetlić utworzone kolumny i wiersze wstawione do tabeli.
- Kliknij prawym przyciskiem myszy tabelę Student i kliknij pozycję Wyświetl kod , aby zobaczyć, jak
Student
model jest mapowy naStudent
schemat tabeli.
Kod asynchroniczny
Programowanie asynchroniczne jest trybem domyślnym dla ASP.NET Core i EF Core.
Serwer internetowy ma ograniczoną liczbę dostępnych wątków, a w sytuacjach dużego obciążenia wszystkie dostępne wątki mogą być używane. W takim przypadku serwer nie może przetworzyć nowych żądań, dopóki wątki nie zostaną zwolnione. W przypadku kodu synchronicznego wiele wątków może być powiązanych, gdy nie działają, ponieważ oczekują na zakończenie operacji we/wy. W przypadku kodu asynchronicznego, gdy proces oczekuje na ukończenie operacji we/wy, jego wątek zostanie zwolniony do użycia przez serwer do przetwarzania innych żądań. W rezultacie kod asynchroniczny umożliwia wydajniejsze wykorzystanie zasobów serwera, a serwer może obsługiwać więcej ruchu bez opóźnień.
Kod asynchroniczny wprowadza niewielką ilość obciążeń w czasie wykonywania. W przypadku sytuacji o niskim natężeniu ruchu wydajność jest niewielka, podczas gdy w przypadku dużych sytuacji drogowych potencjalna poprawa wydajności jest znacząca.
W poniższym kodzie asynchroniczne słowo kluczowe, wartość zwracana, Task
await
słowo kluczowe i ToListAsync
metoda sprawiają, że kod jest wykonywany asynchronicznie.
public async Task OnGetAsync()
{
Students = await _context.Students.ToListAsync();
}
- Słowo
async
kluczowe nakazuje kompilatorowi:- Generowanie wywołań zwrotnych dla części treści metody.
- Utwórz zwrócony obiekt Task.
- Typ zwracany reprezentuje bieżącą
Task
pracę. - Słowo
await
kluczowe powoduje, że kompilator dzieli metodę na dwie części. Pierwsza część kończy się operacją, która została uruchomiona asynchronicznie. Druga część jest umieszczana w metodzie wywołania zwrotnego wywoływanej po zakończeniu operacji. ToListAsync
to asynchroniczna wersjaToList
metody rozszerzenia.
Niektóre kwestie, o których należy pamiętać podczas pisania kodu asynchronicznego, który używa EF Coremetody :
- Tylko instrukcje, które powodują wysyłanie zapytań lub poleceń do bazy danych, są wykonywane asynchronicznie.
ToListAsync
Obejmuje to , ,FirstOrDefaultAsync
SingleOrDefaultAsync
iSaveChangesAsync
. Nie zawiera instrukcji, które po prostu zmieniają elementIQueryable
, na przykładvar students = context.Students.Where(s => s.LastName == "Davolio")
. - Kontekst EF Core nie jest bezpieczny wątkiem: nie próbuj wykonywać wielu operacji równolegle.
- Aby skorzystać z zalet wydajności kodu asynchronicznego, sprawdź, czy pakiety bibliotek (takie jak stronicowanie) używają asynchronicznego, jeśli wywołają EF Core metody wysyłające zapytania do bazy danych.
Aby uzyskać więcej informacji na temat programowania asynchronicznego na platformie .NET, zobacz Async Overview and Asynchronous programming with async and await (Omówienie asynchroniczne i asynchroniczne programowanie asynchroniczne za pomocą asynchronicznego i oczekiwania).
Zagadnienia dotyczące wydajności
Ogólnie rzecz biorąc, strona internetowa nie powinna ładować dowolnej liczby wierszy. Zapytanie powinno używać stronicowania lub podejścia ograniczającego. Na przykład powyższe zapytanie może użyć Take
polecenia , aby ograniczyć zwracane wiersze:
public async Task OnGetAsync()
{
Student = await _context.Students.Take(10).ToListAsync();
}
Wyliczanie dużej tabeli w widoku może zwrócić częściowo skonstruowaną odpowiedź HTTP 200, jeśli wyjątek bazy danych występuje w części przez wyliczenie.
MaxModelBindingCollectionSize wartość domyślna to 1024. Następujące zestawy MaxModelBindingCollectionSize
kodu:
public void ConfigureServices(IServiceCollection services)
{
var myMaxModelBindingCollectionSize = Convert.ToInt32(
Configuration["MyMaxModelBindingCollectionSize"] ?? "100");
services.Configure<MvcOptions>(options =>
options.MaxModelBindingCollectionSize = myMaxModelBindingCollectionSize);
services.AddRazorPages();
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
services.AddDatabaseDeveloperPageExceptionFilter();
}
Zobacz Konfiguracja , aby uzyskać informacje na temat ustawień konfiguracji, takich jak MyMaxModelBindingCollectionSize
.
Stronicowanie zostało omówione w dalszej części samouczka.
Aby uzyskać więcej informacji, zobacz Zagadnienia dotyczące wydajności (EF).
Rejestrowanie SQL platformy Entity Framework Core
Konfiguracja rejestrowania jest często dostarczana za pomocą sekcji Logging
plików appsettings.{Environment}.json
. Aby zarejestrować instrukcje SQL, dodaj "Microsoft.EntityFrameworkCore.Database.Command": "Information"
do appsettings.Development.json
pliku:
{
"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": "*"
}
Po wcześniejszym kodzie JSON instrukcje SQL są wyświetlane w wierszu polecenia i w oknie danych wyjściowych programu Visual Studio.
Aby uzyskać więcej informacji, zobacz Rejestrowanie na platformie .NET Core i ASP.NET Core oraz ten problem z usługą GitHub.
Następne kroki
Używanie narzędzia SQLite do programowania, programu SQL Server dla środowiska produkcyjnego
Jest to pierwszy z serii samouczków, które pokazują, jak używać programu Entity Framework (EF) Core w aplikacji ASP.NET Core Razor Pages . Samouczki tworzą witrynę internetową fikcyjnego uniwersytetu Contoso. Witryna zawiera funkcje, takie jak wstęp dla uczniów, tworzenie kursów i zadania instruktora. W tym samouczku jest używane pierwsze podejście do kodu. Aby uzyskać informacje na temat korzystania z tego samouczka przy użyciu pierwszego podejścia do bazy danych, zobacz ten problem z usługą GitHub.
Pobierz lub wyświetl ukończoną aplikację. Pobierz instrukcje.
Wymagania wstępne
- Jeśli dopiero zaczynasz Razor pracę ze stronami, zapoznaj się z serią samouczków Wprowadzenie do Razor stron przed rozpoczęciem tego samouczka.
- Program Visual Studio 2019 z pakietem roboczym tworzenia aplikacji internetowych i ASP.NET
- Zestaw SDK platformy .NET Core 3.0
Aparaty bazy danych
Instrukcje programu Visual Studio używają programu SQL Server LocalDB — wersji programu SQL Server Express działającej tylko w systemie Windows.
Instrukcje programu Visual Studio Code korzystają z narzędzia SQLite, aparatu bazy danych dla wielu platform.
Jeśli zdecydujesz się używać sqLite, pobierz i zainstaluj narzędzie innej firmy do zarządzania bazą danych SQLite i wyświetlania jej, takiej jak przeglądarka db for SQLite.
Rozwiązywanie problemów
Jeśli napotkasz problem, nie możesz go rozwiązać, porównaj kod z ukończonym projektem. Dobrym sposobem uzyskania pomocy jest opublikowanie pytania do StackOverflow.com przy użyciu tagu ASP.NET Core lub taguEF Core.
Przykładowa aplikacja
Aplikacja wbudowana w te samouczki jest podstawową witryną internetową uniwersytetu. Użytkownicy mogą wyświetlać i aktualizować informacje o uczniach, kursach i instruktorach. Poniżej przedstawiono kilka ekranów utworzonych w samouczku.
Styl interfejsu użytkownika tej witryny jest oparty na wbudowanych szablonach projektów. Samouczek koncentruje się na sposobie używania metody EF Core, a nie dostosowywania interfejsu użytkownika.
Kliknij link w górnej części strony, aby pobrać kod źródłowy ukończonego projektu. Folder cu30 zawiera kod ASP.NET Core 3.0 w samouczku. Pliki odzwierciedlające stan kodu dla samouczków 1–7 można znaleźć w folderze cu30snapshots .
Aby uruchomić aplikację po pobraniu ukończonego projektu:
Skompiluj projekt.
W konsoli Menedżer pakietów (PMC) uruchom następujące polecenie:
Update-Database
Uruchom projekt, aby zainicjować bazę danych.
Tworzenie projektu aplikacji internetowej
- W menu Plik programu Visual Studio wybierz pozycję Nowy>projekt.
- Wybierz pozycję ASP.NET Core Web Application(Podstawowa aplikacja internetowa).
- Nadaj projektowi nazwę ContosoUniversity. Należy użyć tej dokładnej nazwy, w tym wielkich liter, więc przestrzenie nazw są zgodne, gdy kod jest kopiowany i wklejany.
- Wybierz pozycję .NET Core i ASP.NET Core 3.0 na listach rozwijanych, a następnie wybierz pozycję Aplikacja internetowa.
Konfigurowanie stylu witryny
Skonfiguruj nagłówek, stopkę i menu witryny, aktualizując Pages/Shared/_Layout.cshtml
polecenie :
Zmień każde wystąpienie "ContosoUniversity" na "Contoso University". Istnieją trzy wystąpienia.
Home Usuń wpisy menu i Privacy i dodaj wpisy dla pozycji Informacje, Uczniowie, Kursy, Instruktorzy i Działy.
Zmiany są wyróżnione.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2019 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
W Pages/Index.cshtml
pliku zastąp zawartość pliku następującym kodem, aby zastąpić tekst ASP.NET Core tekstem o tej aplikacji:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="row mb-auto">
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 mb-4 ">
<p class="card-text">
Contoso University is a sample application that
demonstrates how to use Entity Framework Core in an
ASP.NET Core Razor Pages web app.
</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column position-static">
<p class="card-text mb-auto">
You can build the application by following the steps in a series of tutorials.
</p>
<p>
<a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column">
<p class="card-text mb-auto">
You can download the completed project from GitHub.
</p>
<p>
<a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
</p>
</div>
</div>
</div>
</div>
Uruchom aplikację, aby sprawdzić, czy zostanie wyświetlona home strona.
Model danych
W poniższych sekcjach tworzysz model danych:
Student może zarejestrować się w dowolnej liczbie kursów, a kurs może mieć dowolną liczbę uczniów zarejestrowanych w nim.
Jednostka Student
Utwórz folder Models w folderze projektu.
Utwórz
Models/Student.cs
za pomocą następującego kodu: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; } } }
Właściwość ID
staje się kolumną klucza podstawowego tabeli bazy danych, która odpowiada tej klasie. Domyślnie EF Core interpretuje właściwość o nazwie ID
lub classnameID
jako klucz podstawowy. Dlatego alternatywna nazwa automatycznie rozpoznawana dla klucza podstawowego Student
klasy to StudentID
. Aby uzyskać więcej informacji, zobacz EF Core — Klucze.
Właściwość Enrollments
jest właściwością nawigacji. Właściwości nawigacji przechowują inne jednostki powiązane z tą jednostką. W takim przypadku Enrollments
właściwość Student
jednostki przechowuje wszystkie Enrollment
jednostki powiązane z tym uczniem. Jeśli na przykład wiersz Student w bazie danych zawiera dwa powiązane wiersze rejestracji, Enrollments
właściwość nawigacji zawiera te dwie jednostki rejestracji.
W bazie danych wiersz rejestracji jest powiązany z wierszem Student, jeśli jego kolumna StudentID zawiera wartość identyfikatora ucznia. Załóżmy na przykład, że wiersz Student ma identyfikator =1. Powiązane wiersze rejestracji będą miały identyfikator StudentID = 1. StudentID jest kluczem obcym w tabeli Rejestracja.
Właściwość jest zdefiniowana Enrollments
jako ICollection<Enrollment>
, ponieważ może istnieć wiele powiązanych jednostek rejestracji. Możesz użyć innych typów kolekcji, takich jak List<Enrollment>
lub HashSet<Enrollment>
. Gdy ICollection<Enrollment>
jest używany, EF Core domyślnie tworzy HashSet<Enrollment>
kolekcję.
Jednostka Rejestracja
Utwórz Models/Enrollment.cs
za pomocą następującego kodu:
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; }
}
}
Właściwość jest kluczem podstawowym. Ta EnrollmentID
jednostka używa classnameID
wzorca zamiast ID
samego siebie. W przypadku modelu danych produkcyjnych wybierz jeden wzorzec i użyj go spójnie. W tym samouczku użyto obu tych elementów, aby zilustrować, że obie te elementy działają. Użycie ID
bez classname
ułatwia implementowanie niektórych rodzajów zmian modelu danych.
Właściwość Grade
to enum
. Znak zapytania po Grade
deklaracji typu wskazuje, że Grade
właściwość jest dopuszczana do wartości null. Ocena o wartości null różni się od klasy zerowej — wartość null oznacza, że ocena nie jest znana lub nie została jeszcze przypisana.
Właściwość StudentID
jest kluczem obcym, a odpowiadająca mu właściwość nawigacji to Student
. Jednostka Enrollment
jest skojarzona z jedną Student
jednostką, więc właściwość zawiera jedną Student
jednostkę.
Właściwość CourseID
jest kluczem obcym, a odpowiadająca mu właściwość nawigacji to Course
. Jednostka Enrollment
jest skojarzona z jedną jednostką Course
.
EF Core interpretuje właściwość jako klucz obcy, jeśli ma nazwę <navigation property name><primary key property name>
. Na przykładStudentID
jest kluczem obcym Student
właściwości nawigacji, ponieważ Student
kluczem podstawowym jednostki jest ID
. Właściwości klucza obcego mogą również mieć nazwę <primary key property name>
. Na przykład ponieważ CourseID
Course
kluczem podstawowym jednostki jest CourseID
.
Jednostka Course
Utwórz Models/Course.cs
za pomocą następującego kodu:
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; }
}
}
Właściwość Enrollments
jest właściwością nawigacji. Jednostka Course
może być powiązana z dowolną Enrollment
liczbą jednostek.
Atrybut DatabaseGenerated
umożliwia aplikacji określenie klucza podstawowego zamiast generowania jej przez bazę danych.
Skompiluj projekt, aby sprawdzić, czy nie ma żadnych błędów kompilatora.
Strony ucznia szkieletu
W tej sekcji użyjesz narzędzia do tworzenia szkieletów ASP.NET Core, aby wygenerować następujące elementy:
- Klasa EF Corekontekstu . Kontekst jest główną klasą, która koordynuje funkcje programu Entity Framework dla danego modelu danych. Pochodzi z
Microsoft.EntityFrameworkCore.DbContext
klasy . - Razor strony obsługujące operacje Create, Read, Update i Delete (CRUD) dla
Student
jednostki.
- Utwórz folder Students w folderze Pages.
- W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Pages/Students i wybierz polecenie Dodaj>nowy element szkieletowy.
- W oknie dialogowym Dodawanie szkieletu wybierz pozycję Razor Strony przy użyciu programu Entity Framework (CRUD)>ADD.
- W oknie dialogowym Dodawanie Razor stron przy użyciu programu Entity Framework (CRUD):
- Z listy rozwijanej Klasa modelu wybierz pozycję Student (ContosoUniversity.Models).
- W wierszu Klasy kontekstu danych wybierz + znak (plus).
- Zmień nazwę kontekstu danych z ContosoUniversity.Models.ContosoUniversityContext na ContosoUniversity.Data.SchoolContext.
- Wybierz Dodaj.
Następujące pakiety są instalowane automatycznie:
Microsoft.VisualStudio.Web.CodeGeneration.Design
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.Extensions.Logging.Debug
Microsoft.EntityFrameworkCore.Tools
Jeśli masz problem z poprzednim krokiem, skompiluj projekt i spróbuj ponownie wykonać krok szkieletu.
Proces tworzenia szkieletów:
- Tworzy Razor strony w folderze Pages/Students :
Create.cshtml
iCreate.cshtml.cs
Delete.cshtml
iDelete.cshtml.cs
Details.cshtml
iDetails.cshtml.cs
Edit.cshtml
iEdit.cshtml.cs
Index.cshtml
iIndex.cshtml.cs
- Tworzy
Data/SchoolContext.cs
polecenie . - Dodaje kontekst do wstrzykiwania zależności w pliku
Startup.cs
. - Dodaje parametry połączenia bazy danych do elementu
appsettings.json
.
Parametry połączenia bazy danych
Plik appsettings.json
określa parametry połączenia SQL Server LocalDB.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=SchoolContext6;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
LocalDB to uproszczona wersja aparatu bazy danych SQL Server Express i jest przeznaczona do tworzenia aplikacji, a nie do użytku produkcyjnego. Domyślnie baza danych LocalDB tworzy pliki .mdf w C:/Users/<user>
katalogu.
Aktualizowanie klasy kontekstu bazy danych
Główną klasą, która koordynuje EF Core funkcjonalność danego modelu danych, jest klasa kontekstu bazy danych. Kontekst pochodzi z elementu Microsoft.EntityFrameworkCore.DbContext. Kontekst określa, które jednostki są uwzględnione w modelu danych. W tym projekcie klasa nosi nazwę SchoolContext
.
Zaktualizuj Data/SchoolContext.cs
za pomocą następującego kodu:
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext (DbContextOptions<SchoolContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
Wyróżniony DbSet<TEntity> kod tworzy właściwość dla każdego zestawu jednostek. Terminologia EF Core :
- Zestaw jednostek zwykle odpowiada tabeli bazy danych.
- Jednostka odpowiada wierszowi w tabeli.
Ponieważ zestaw jednostek zawiera wiele jednostek, właściwości DBSet powinny być nazwami mnogimi. Ponieważ narzędzie tworzenia szkieletu utworzyło zestawStudent
DBSet, ten krok zmienia go na liczbę mnogą Students
.
Aby kod Razor Pages był zgodny z nową nazwą zestawu DBSet, wprowadź globalną zmianę w całym projekcie _context.Student
na _context.Students
. Istnieje 8 wystąpień.
Skompiluj projekt, aby sprawdzić, czy nie ma żadnych błędów kompilatora.
Startup.cs
ASP.NET Core jest kompilowany za pomocą wstrzykiwania zależności. Usługi (takie jak EF Core kontekst bazy danych) są rejestrowane za pomocą wstrzykiwania zależności podczas uruchamiania aplikacji. Składniki, które wymagają tych usług (takich jak Razor Pages), są udostępniane za pośrednictwem parametrów konstruktora. Kod konstruktora, który pobiera wystąpienie kontekstu bazy danych, jest wyświetlany w dalszej części samouczka.
Narzędzie do tworzenia szkieletów automatycznie zarejestrowało klasę kontekstu za pomocą kontenera wstrzykiwania zależności.
W
ConfigureServices
pliku wyróżnione wiersze zostały dodane przez szkielet:public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddDbContext<SchoolContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SchoolContext"))); }
Nazwa parametry połączenia jest przekazywana do kontekstu przez wywołanie metody w DbContextOptions obiekcie. W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje parametry połączenia z appsettings.json
pliku.
Tworzenie bazy danych
Zaktualizuj Program.cs
bazę danych, aby utworzyć ją, jeśli nie istnieje:
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
namespace ContosoUniversity
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
CreateDbIfNotExists(host);
host.Run();
}
private static void CreateDbIfNotExists(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
// DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred creating the DB.");
}
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Metoda EnsureCreated nie podejmuje żadnej akcji, jeśli istnieje baza danych kontekstu. Jeśli baza danych nie istnieje, tworzy bazę danych i schemat. EnsureCreated
włącza następujący przepływ pracy do obsługi zmian modelu danych:
- Usuń bazę danych. Wszystkie istniejące dane zostaną utracone.
- Zmień model danych. Na przykład dodaj
EmailAddress
pole. - Uruchom aplikację.
EnsureCreated
tworzy bazę danych przy użyciu nowego schematu.
Ten przepływ pracy działa dobrze na wczesnym etapie opracowywania, gdy schemat jest szybko rozwijany, o ile nie trzeba zachowywać danych. Sytuacja jest inna, gdy należy zachować dane wprowadzone w bazie danych. W takim przypadku należy użyć migracji.
W dalszej części serii samouczków usuniesz bazę danych, która została utworzona przez EnsureCreated
program i zamiast tego użyjesz migracji. Nie można zaktualizować bazy danych utworzonej przez EnsureCreated
program przy użyciu migracji.
Testowanie aplikacji
- Uruchom aplikację.
- Wybierz link Uczniowie, a następnie pozycję Utwórz nowy.
- Przetestuj linki Edytuj, Szczegóły i Usuń.
Inicjowanie bazy danych
Metoda EnsureCreated
tworzy pustą bazę danych. Ta sekcja dodaje kod, który wypełnia bazę danych danymi testowymi.
Utwórz Data/DbInitializer.cs
za pomocą następującego kodu:
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using System;
using System.Linq;
namespace ContosoUniversity.Data
{
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
context.Database.EnsureCreated();
// Look for any students.
if (context.Students.Any())
{
return; // DB has been seeded
}
var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
};
context.Students.AddRange(students);
context.SaveChanges();
var courses = new Course[]
{
new Course{CourseID=1050,Title="Chemistry",Credits=3},
new Course{CourseID=4022,Title="Microeconomics",Credits=3},
new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
new Course{CourseID=1045,Title="Calculus",Credits=4},
new Course{CourseID=3141,Title="Trigonometry",Credits=4},
new Course{CourseID=2021,Title="Composition",Credits=3},
new Course{CourseID=2042,Title="Literature",Credits=4}
};
context.Courses.AddRange(courses);
context.SaveChanges();
var enrollments = new Enrollment[]
{
new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
new Enrollment{StudentID=3,CourseID=1050},
new Enrollment{StudentID=4,CourseID=1050},
new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
new Enrollment{StudentID=6,CourseID=1045},
new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
};
context.Enrollments.AddRange(enrollments);
context.SaveChanges();
}
}
}
Kod sprawdza, czy w bazie danych znajdują się uczniowie. Jeśli nie ma uczniów, dodaje dane testowe do bazy danych. Tworzy dane testowe w tablicach, a nie List<T>
kolekcje w celu zoptymalizowania wydajności.
W
Program.cs
pliku zastąp wywołanieEnsureCreated
wywołaniemDbInitializer.Initialize
:// context.Database.EnsureCreated(); DbInitializer.Initialize(context);
Zatrzymaj aplikację, jeśli jest uruchomiona, i uruchom następujące polecenie w konsoli Menedżer pakietów (PMC):
Drop-Database
Ponownie uruchom aplikację.
Wybierz stronę Uczniowie, aby wyświetlić dane rozstawione.
Wyświetlanie bazy danych
- Otwórz program SQL Server Eksplorator obiektów (SSOX) z menu Widok w programie Visual Studio.
- W programie SSOX wybierz pozycję (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Nazwa bazy danych jest generowana na podstawie podanej wcześniej nazwy kontekstu oraz kreski i identyfikatora GUID.
- Rozwiń węzeł Tabele.
- Kliknij prawym przyciskiem myszy tabelę Student i kliknij pozycję Wyświetl dane , aby wyświetlić utworzone kolumny i wiersze wstawione do tabeli.
- Kliknij prawym przyciskiem myszy tabelę Student i kliknij pozycję Wyświetl kod , aby zobaczyć, jak
Student
model jest mapowy naStudent
schemat tabeli.
Kod asynchroniczny
Programowanie asynchroniczne jest trybem domyślnym dla ASP.NET Core i EF Core.
Serwer internetowy ma ograniczoną liczbę dostępnych wątków, a w sytuacjach dużego obciążenia wszystkie dostępne wątki mogą być używane. W takim przypadku serwer nie może przetworzyć nowych żądań, dopóki wątki nie zostaną zwolnione. W przypadku kodu synchronicznego wiele wątków może być powiązanych, gdy nie wykonują żadnej pracy, ponieważ oczekują na zakończenie operacji we/wy. W przypadku kodu asynchronicznego, gdy proces oczekuje na ukończenie operacji we/wy, jego wątek zostanie zwolniony do użycia przez serwer do przetwarzania innych żądań. W rezultacie kod asynchroniczny umożliwia wydajniejsze wykorzystanie zasobów serwera, a serwer może obsługiwać więcej ruchu bez opóźnień.
Kod asynchroniczny wprowadza niewielką ilość obciążeń w czasie wykonywania. W przypadku sytuacji o niskim natężeniu ruchu wydajność jest niewielka, podczas gdy w przypadku dużych sytuacji drogowych potencjalna poprawa wydajności jest znacząca.
W poniższym kodzie asynchroniczne słowo kluczowe, wartość zwracana, Task<T>
await
słowo kluczowe i ToListAsync
metoda sprawiają, że kod jest wykonywany asynchronicznie.
public async Task OnGetAsync()
{
Students = await _context.Students.ToListAsync();
}
- Słowo
async
kluczowe nakazuje kompilatorowi:- Generowanie wywołań zwrotnych dla części treści metody.
- Utwórz zwrócony obiekt Task.
- Typ zwracany reprezentuje bieżącą
Task<T>
pracę. - Słowo
await
kluczowe powoduje, że kompilator dzieli metodę na dwie części. Pierwsza część kończy się operacją, która została uruchomiona asynchronicznie. Druga część jest umieszczana w metodzie wywołania zwrotnego wywoływanej po zakończeniu operacji. ToListAsync
to asynchroniczna wersjaToList
metody rozszerzenia.
Niektóre kwestie, o których należy pamiętać podczas pisania kodu asynchronicznego, który używa EF Coremetody :
- Tylko instrukcje, które powodują wysyłanie zapytań lub poleceń do bazy danych, są wykonywane asynchronicznie.
ToListAsync
Obejmuje to , ,FirstOrDefaultAsync
SingleOrDefaultAsync
iSaveChangesAsync
. Nie zawiera instrukcji, które po prostu zmieniają elementIQueryable
, na przykładvar students = context.Students.Where(s => s.LastName == "Davolio")
. - Kontekst EF Core nie jest bezpieczny wątkiem: nie próbuj wykonywać wielu operacji równolegle.
- Aby skorzystać z zalet wydajności kodu asynchronicznego, sprawdź, czy pakiety bibliotek (takie jak stronicowanie) używają asynchronicznego, jeśli wywołają EF Core metody wysyłające zapytania do bazy danych.
Aby uzyskać więcej informacji na temat programowania asynchronicznego na platformie .NET, zobacz Async Overview and Asynchronous programming with async and await (Omówienie asynchroniczne i asynchroniczne programowanie asynchroniczne za pomocą asynchronicznego i oczekiwania).