Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Note
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z aktualną wersją, zobacz artykuł w wersji .NET 10.
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.
Prerequisites
- Jeśli dopiero zaczynasz Razor pracę ze stronami, zapoznaj się z serią samouczków Wprowadzenie do Razor stron przed rozpoczęciem tego samouczka.
- w programie Visual Studio
- Visual Studio Code
Program Visual Studio 2022 z pakietem roboczym tworzenia aplikacji ASP.NET i aplikacji internetowych.
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.
Troubleshooting
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.
- w programie Visual Studio
- Visual Studio Code
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
- w programie Visual Studio
- Visual Studio Code
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ść w polu
ContosoUniversityprojektu. 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.cshtmlpliku 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 strona główna.
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.csza 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.
StudentIDjest 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ż CourseIDCourse 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, public string? RequestId { get; set; }Pages/Error.cshtml.cs 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
Studentjednostki.
- w programie Visual Studio
- Visual Studio Code
- Utwórz folder Pages/Students.
- W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Pages/Students i wybierz polecenie > szkieletowy.
-
W oknie dialogowym Dodawanie nowego elementu szkieletu:
- Na lewej karcie wybierz pozycję Zainstalowane > wspólne >Razor strony
- Wybierz pozycję 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
SchoolContextsię 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.SqlServerMicrosoft.EntityFrameworkCore.ToolsMicrosoft.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.cshtmliCreate.cshtml.cs -
Delete.cshtmliDelete.cshtml.cs -
Details.cshtmliDetails.cshtml.cs -
Edit.cshtmliEdit.cshtml.cs -
Index.cshtmliIndex.cshtml.cs
-
- Tworzy
Data/SchoolContext.cspolecenie . - 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.
- w programie Visual Studio
- Visual Studio Code
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> StudentDbSet<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
SchoolContextzostał zainicjowany, ale przed zabezpieczeniem modelu i użytym do zainicjowania kontekstu. - Jest to wymagane, ponieważ w dalszej części samouczka
Studentjednostka 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.
- w programie Visual Studio
- Visual Studio Code
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:
- w programie Visual Studio
- Visual Studio Code
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:
- w programie Visual Studio
- Visual Studio Code
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
EmailAddresspole. - Uruchom aplikację.
-
EnsureCreatedtworzy 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.cspliku//usuńDbInitializer.Initializez wiersza:
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
DbInitializer.Initialize(context);
}
- w programie Visual Studio
- Visual Studio Code
Zatrzymaj aplikację, jeśli jest uruchomiona, i uruchom następujące polecenie w konsoli Menedżer pakietów (PMC):
Drop-Database -ConfirmOdpowiedz,
Yaby usunąć bazę danych.
- Ponownie uruchom aplikację.
- Wybierz stronę Uczniowie, aby wyświetlić dane rozstawione.
Wyświetlanie bazy danych
- w programie Visual Studio
- Visual Studio Code
- 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
Studentmodel jest mapowy naStudentschemat 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że kod jest wykonywany asynchronicznie.
public async Task OnGetAsync()
{
Students = await _context.Students.ToListAsync();
}
- Słowo
asynckluczowe nakazuje kompilatorowi:- Generowanie wywołań zwrotnych dla części treści metody.
- Utwórz zwrócony obiekt Task.
- Typ zwracany reprezentuje bieżącą
Taskpracę. - Słowo
awaitkluczowe 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. -
ToListAsyncto asynchroniczna wersjaToListmetody 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.
ToListAsyncObejmuje to , ,SingleOrDefaultAsyncFirstOrDefaultAsynciSaveChangesAsync. 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).
Warning
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).
Dalsze 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.
Prerequisites
- Jeśli dopiero zaczynasz Razor pracę ze stronami, zapoznaj się z serią samouczków Wprowadzenie do Razor stron przed rozpoczęciem tego samouczka.
- w programie Visual Studio
- Visual Studio Code
Program Visual Studio 2022 z pakietem roboczym tworzenia aplikacji ASP.NET i aplikacji internetowych.
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.
Troubleshooting
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.
- w programie Visual Studio
- Visual Studio Code
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
- w programie Visual Studio
- Visual Studio Code
- 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ść w polu
ContosoUniversityprojektu. Należy użyć tej dokładnej nazwy, w tym wielkich liter, więc każdynamespacez nich jest zgodny podczas kopiowania kodu. - Wybierz 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.cshtmlpliku 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 strona główna.
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.csza 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.
StudentIDjest 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ż CourseIDCourse 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
Studentjednostki.
- w programie Visual Studio
- Visual Studio Code
- Utwórz folder Pages/Students.
- W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Pages/Students i wybierz polecenie > szkieletowy.
-
W oknie dialogowym Dodawanie nowego elementu szkieletu:
- Na lewej karcie wybierz pozycję Zainstalowane > wspólne >Razor strony
- Wybierz pozycję 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
SchoolContextsię 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.SqlServerMicrosoft.EntityFrameworkCore.ToolsMicrosoft.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.cshtmliCreate.cshtml.cs -
Delete.cshtmliDelete.cshtml.cs -
Details.cshtmliDetails.cshtml.cs -
Edit.cshtmliEdit.cshtml.cs -
Index.cshtmliIndex.cshtml.cs
-
- Tworzy
Data/SchoolContext.cspolecenie . - 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.
- w programie Visual Studio
- Visual Studio Code
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> StudentDbSet<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
SchoolContextzostał zainicjowany, ale przed zabezpieczeniem modelu i użytym do zainicjowania kontekstu. - Jest to wymagane, ponieważ w dalszej części samouczka
Studentjednostka 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.
- w programie Visual Studio
- Visual Studio Code
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:
- w programie Visual Studio
- Visual Studio Code
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
EmailAddresspole. - Uruchom aplikację.
-
EnsureCreatedtworzy 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.cspliku//usuńDbInitializer.Initializez wiersza:context.Database.EnsureCreated(); DbInitializer.Initialize(context);
- w programie Visual Studio
- Visual Studio Code
Zatrzymaj aplikację, jeśli jest uruchomiona, i uruchom następujące polecenie w konsoli Menedżer pakietów (PMC):
Drop-Database -ConfirmOdpowiedz,
Yaby usunąć bazę danych.
- Ponownie uruchom aplikację.
- Wybierz stronę Uczniowie, aby wyświetlić dane rozstawione.
Wyświetlanie bazy danych
- w programie Visual Studio
- Visual Studio Code
- 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
Studentmodel jest mapowy naStudentschemat 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że kod jest wykonywany asynchronicznie.
public async Task OnGetAsync()
{
Students = await _context.Students.ToListAsync();
}
- Słowo
asynckluczowe nakazuje kompilatorowi:- Generowanie wywołań zwrotnych dla części treści metody.
- Utwórz zwrócony obiekt Task.
- Typ zwracany reprezentuje bieżącą
Taskpracę. - Słowo
awaitkluczowe 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. -
ToListAsyncto asynchroniczna wersjaToListmetody 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.
ToListAsyncObejmuje to , ,SingleOrDefaultAsyncFirstOrDefaultAsynciSaveChangesAsync. 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 MaxModelBindingCollectionSizekodu:
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 i ASP.NET Core oraz ten problem z usługą GitHub.
Dalsze 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.
Prerequisites
- Jeśli dopiero zaczynasz Razor pracę ze stronami, zapoznaj się z serią samouczków Wprowadzenie do Razor stron przed rozpoczęciem tego samouczka.
- w programie Visual Studio
- Visual Studio Code
Program Visual Studio 2022 z pakietem roboczym tworzenia aplikacji ASP.NET i aplikacji internetowych.
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.
Troubleshooting
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 .
- w programie Visual Studio
- Visual Studio Code
Aby uruchomić aplikację po pobraniu ukończonego projektu:
Skompiluj projekt.
W konsoli Menedżer pakietów (PMC) uruchom następujące polecenie:
Update-DatabaseUruchom projekt, aby zainicjować bazę danych.
Tworzenie projektu aplikacji internetowej
- w programie Visual Studio
- Visual Studio Code
- W menu Plik programu Visual Studio wybierz pozycję Nowy>.
- 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.cshtmlpolecenie :
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.cshtmlpliku 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 strona główna.
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.csza 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ż CourseIDCourse 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.DbContextklasy . -
Razor strony obsługujące operacje Create, Read, Update i Delete (CRUD) dla
Studentjednostki.
- w programie Visual Studio
- Visual Studio Code
- Utwórz folder Students w folderze Pages.
- W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Pages/Students i wybierz polecenie > 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.DesignMicrosoft.EntityFrameworkCore.SqlServerMicrosoft.Extensions.Logging.DebugMicrosoft.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.cshtmliCreate.cshtml.cs -
Delete.cshtmliDelete.cshtml.cs -
Details.cshtmliDetails.cshtml.cs -
Edit.cshtmliEdit.cshtml.cs -
Index.cshtmliIndex.cshtml.cs
-
- Tworzy
Data/SchoolContext.cspolecenie . - 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
- w programie Visual Studio
- Visual Studio Code
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 programie Visual Studio
- Visual Studio Code
W
ConfigureServicespliku 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
EmailAddresspole. - Uruchom aplikację.
-
EnsureCreatedtworzy 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.cspliku zastąp wywołanieEnsureCreatedwywołaniemDbInitializer.Initialize:// context.Database.EnsureCreated(); DbInitializer.Initialize(context);
- w programie Visual Studio
- Visual Studio Code
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
- w programie Visual Studio
- Visual Studio Code
- 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
Studentmodel jest mapowy naStudentschemat 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że kod jest wykonywany asynchronicznie.
public async Task OnGetAsync()
{
Students = await _context.Students.ToListAsync();
}
- Słowo
asynckluczowe 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
awaitkluczowe 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. -
ToListAsyncto asynchroniczna wersjaToListmetody 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.
ToListAsyncObejmuje to , ,SingleOrDefaultAsyncFirstOrDefaultAsynciSaveChangesAsync. 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).