Samouczek: rozpoczynanie pracy z EF Core aplikacją internetową MVC ASP.NET

Przez Tom Dykstra i Rick Anderson

W tym samouczku przedstawiono model ASP.NET Core MVC i program Entity Framework Core z kontrolerami i widokami. Strony Razor to alternatywny model programowania. W przypadku nowego projektu programowania zalecamy używanie stron Razor w zamiast modelu MVC z kontrolerami i widokami. Zobacz wersję tego samouczka dla stron Razor. Każdy z tych samouczków obejmuje pewne materiały, których nie ma w drugim:

Niektóre elementy tego samouczka modelu MVC, które nie są dostępne w przypadku stron Razor:

  • Implementowanie dziedziczenia w modelu danych
  • Wykonywanie pierwotnych zapytań SQL
  • Używanie dynamicznych zapytań LINQ w celu uproszczenia kodu

Niektóre elementy samouczka dotyczącego stron Razor, których nie ma w tym samouczku:

  • Ładowanie powiązanych danych za pomocą metody Select
  • Najlepsze rozwiązania dotyczące platformy EF.

Przykładowa aplikacja internetowa Contoso University pokazuje, jak utworzyć aplikację internetową platformy ASP.NET Core MVC przy użyciu platformy Entity Framework (EF) Core i programu Visual Studio.

Przykładowa aplikacja to witryna internetowa fikcyjnego uniwersytetu Contoso. Obejmuje ona funkcje, takie jak wstęp dla uczniów, tworzenie kursów i zadania instruktora. Jest to pierwszy z serii samouczków, które wyjaśniają, jak utworzyć przykładową aplikację Contoso University.

Wymagania wstępne

Ten samouczek nie został zaktualizowany dla ASP.NET Core 6 lub nowszego. Instrukcje samouczka nie będą działać poprawnie, jeśli utworzysz projekt przeznaczony dla ASP.NET Core 6 lub nowszej wersji. Na przykład szablony sieci Web ASP.NET Core 6 i nowszych używają minimalnego modelu hostingu, który łączy Startup.cs się i Program.cs w jeden Program.cs plik.

Kolejną różnicą wprowadzoną na platformie .NET 6 jest funkcja NRT (typy referencyjne dopuszczane do wartości null). Szablony projektów domyślnie włączają tę funkcję. Problemy mogą wystąpić, gdy program EF uważa, że właściwość musi być wymagana na platformie .NET 6, która jest dopuszczana do wartości null na platformie .NET 5. Na przykład strona Tworzenie ucznia zakończy się niepowodzeniem w trybie dyskretnym, chyba że Enrollments właściwość ma wartość null lub asp-validation-summary tag pomocnika zostanie zmieniony z ModelOnly na All.

Na potrzeby tego samouczka zalecamy zainstalowanie i użycie zestawu .NET 5 SDK. Dopóki ten samouczek nie zostanie zaktualizowany, zobacz Razor Strony z programem Entity Framework Core w programie ASP.NET Core — samouczek 1 z 8 , aby dowiedzieć się, jak używać platformy Entity Framework z programem ASP.NET Core 6 lub nowszym.

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 i rozwiązywanie problemów

Jeśli napotkasz problem, którego nie możesz rozwiązać, zazwyczaj możesz znaleźć rozwiązanie, porównując kod z ukończonym projektem. Aby uzyskać listę typowych błędów i sposób ich rozwiązywania, zobacz sekcję Rozwiązywanie problemów z ostatnim samouczkiem z serii. Jeśli nie znajdziesz tam potrzebnych informacji, możesz opublikować pytanie, aby StackOverflow.com dla platformy ASP.NET Core lub EF Core.

Napiwek

Jest to seria 10 samouczków, z których każda opiera się na tym, co zostało wykonane we wcześniejszych samouczkach. Rozważ zapisanie kopii projektu po zakończeniu każdego pomyślnego ukończenia samouczka. Następnie, jeśli wystąpią problemy, możesz zacząć od poprzedniego samouczka zamiast wracać do początku całej serii.

Aplikacja internetowa Contoso University

Aplikacja wbudowana w te samouczki jest podstawową witryną internetową uniwersytetu.

Użytkownicy mogą wyświetlać i aktualizować informacje o uczniach, kursach i instruktorach. Oto kilka ekranów w aplikacji:

Students Index page

Students Edit page

Tworzenie aplikacji internetowej

  1. Uruchom program Visual Studio i wybierz pozycję Utwórz nowy projekt.
  2. W oknie dialogowym Tworzenie nowego projektu wybierz pozycję ASP.NET Core Web Application>Next (Dalej).
  3. 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żdy namespace z nich jest zgodny podczas kopiowania kodu.
  4. Wybierz pozycję Utwórz.
  5. W oknie dialogowym Tworzenie nowej aplikacji internetowej platformy ASP.NET Core wybierz pozycję:
    1. Platforma .NET Core i ASP.NET Core 5.0 na listach rozwijanych.
    2. ASP.NET Core Web App (Model-View-Controller).
    3. UtwórzNew ASP.NET Core Project dialog

Konfigurowanie stylu witryny

Kilka podstawowych zmian skonfiguruj menu witryny, układ i stronę główną.

Otwórz Views/Shared/_Layout.cshtml plik i wprowadź następujące zmiany:

  • Zmień każde wystąpienie elementu ContosoUniversity na Contoso University. Istnieją trzy wystąpienia.
  • Dodaj pozycje menu Informacje, Uczniowie, Kursy, Instruktorzy i Działy oraz usuń Privacy wpis menu.

Powyższe zmiany są wyróżnione w następującym kodzie:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Contoso University</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

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

W Views/Home/Index.cshtmlpliku zastąp zawartość pliku następującym znacznikiem:

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

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

Naciśnij klawisze CTRL+F5, aby uruchomić projekt, lub wybierz polecenie Debuguj > start bez debugowania z menu. Strona główna jest wyświetlana z kartami stron utworzonych w tym samouczku.

Contoso University home page

EF Core Pakiety NuGet

W tym samouczku jest używany program SQL Server, a pakiet dostawcy to Microsoft.EntityFrameworkCore.SqlServer.

Pakiet EF SQL Server i jego zależności Microsoft.EntityFrameworkCore oraz Microsoft.EntityFrameworkCore.Relational, zapewniają obsługę środowiska uruchomieniowego dla platformy EF.

Dodaj pakiet NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore. W konsoli Menedżer pakietów (PMC) wprowadź następujące polecenia, aby dodać pakiety NuGet:

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

Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore Pakiet NuGet udostępnia oprogramowanie pośredniczące ASP.NET Core dla EF Core stron błędów. To oprogramowanie pośredniczące pomaga wykrywać i diagnozować błędy związane z migracjami EF Core .

Aby uzyskać informacje o innych dostawcach baz danych dostępnych dla EF Coreprogramu , zobacz Dostawcy baz danych.

Tworzenie modelu danych

Dla tej aplikacji są tworzone następujące klasy jednostek:

Course-Enrollment-Student data model diagram

Powyższe jednostki mają następujące relacje:

  • Relacja jeden do wielu między jednostkami Student i Enrollment . Student może być zarejestrowany w dowolnej liczbie kursów.
  • Relacja jeden do wielu między jednostkami Course i Enrollment . Kurs może mieć dowolną liczbę uczniów zarejestrowanych w nim.

W poniższych sekcjach tworzona jest klasa dla każdej z tych jednostek.

Jednostka Student

Student entity diagram

W folderze Models utwórz klasę Student przy użyciu 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 jest kolumną klucza podstawowego (PK) tabeli bazy danych, która odpowiada tej klasie. Domyślnie program EF interpretuje właściwość o nazwie ID lub classnameID jako klucz podstawowy. Na przykład klucz PK może mieć nazwę StudentID zamiast ID.

Właściwość Enrollments jest właściwością nawigacji. Właściwości nawigacji przechowują inne jednostki powiązane z tą jednostką. Enrollments Właściwość Student jednostki:

  • Zawiera wszystkie Enrollment jednostki powiązane z jednostką Student .
  • Jeśli określony Student wiersz w bazie danych ma dwa powiązane Enrollment wiersze:
    • Właściwość Student nawigacji tej Enrollments jednostki zawiera te dwie Enrollment jednostki.

Enrollment wiersze zawierają wartość PK ucznia w kolumnie klucza obcego StudentID (FK).

Jeśli właściwość nawigacji może zawierać wiele jednostek:

  • Typ musi być listą, taką jak ICollection<T>, List<T>lub HashSet<T>.
  • Jednostki można dodawać, usuwać i aktualizować.

Relacje nawigacji wiele do wielu i jeden do wielu mogą zawierać wiele jednostek. Gdy ICollection<T> jest używany, program EF domyślnie tworzy HashSet<T> kolekcję.

Jednostka Rejestracja

Enrollment entity diagram

W folderze Models utwórz klasę Enrollment przy użyciu 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ść EnrollmentID jest kluczem PK. Ta jednostka używa classnameID wzorca zamiast ID samego siebie. Jednostka użyła StudentID wzorca. Niektórzy deweloperzy wolą używać jednego wzorca w całym modelu danych. W tym samouczku odmiana ilustruje, że można użyć dowolnego wzorca. W późniejszym samouczku pokazano, jak użycie bez ID nazwy klasy ułatwia implementowanie dziedziczenia w modelu danych.

Właściwość Grade to enum. Grade Po ? deklaracji typu wskazuje, że Grade właściwość jest dopuszczana do wartości null. Ocena, która różni się null od klasy zerowej. null oznacza, że ocena nie jest znana lub nie została jeszcze przypisana.

Właściwość StudentID jest kluczem obcym (FK), a odpowiadająca mu właściwość nawigacji to Student. Jednostka Enrollment jest skojarzona z jedną Student jednostką, więc właściwość może przechowywać tylko jedną Student jednostkę. Różni się to od Student.Enrollments właściwości nawigacji, która może zawierać wiele Enrollment jednostek.

Właściwość CourseID jest kluczem FK, a odpowiadająca jej właściwość nawigacji to Course. Jednostka Enrollment jest skojarzona z jedną jednostką Course .

Platforma Entity Framework interpretuje właściwość jako właściwość FK, jeśli ma nazwę właściwości nawigacji nazwa <><właściwości klucza> podstawowego. Na przykład StudentID dla Student właściwości nawigacji, ponieważ Student klucz PK jednostki to ID. Właściwości klucza FK mogą być również nazwane <nazwą> właściwości klucza podstawowego. Na przykład ponieważ CourseID klucz Course PK jednostki to CourseID.

Jednostka Course

Course entity diagram

W folderze Models utwórz klasę Course przy użyciu 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 został wyjaśniony w późniejszym samouczku. Ten atrybut umożliwia wprowadzenie klucza PK dla kursu zamiast generowania bazy danych.

Tworzenie kontekstu bazy danych

Główną klasą, która koordynuje funkcje ef dla danego modelu danych, jest DbContext klasa kontekstu bazy danych. Ta klasa jest tworzona przez wyprowadzanie z Microsoft.EntityFrameworkCore.DbContext klasy . Klasa pochodna DbContext określa, które jednostki są uwzględnione w modelu danych. Niektóre zachowania ef można dostosować. W tym projekcie klasa nosi nazwę SchoolContext.

W folderze projektu utwórz folder o nazwie Data.

W folderze Dane utwórz klasę SchoolContext z następującym kodem:

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

Powyższy kod tworzy DbSet właściwość dla każdego zestawu jednostek. W terminologii ef:

  • Zestaw jednostek zwykle odpowiada tabeli bazy danych.
  • Jednostka odpowiada wierszowi w tabeli.

Instrukcje DbSet<Enrollment> i DbSet<Course> mogą zostać pominięte i będą działać tak samo. Program EF uwzględnia je niejawnie, ponieważ:

  • Jednostka Student odwołuje się do Enrollment jednostki.
  • Jednostka Enrollment odwołuje się do Course jednostki.

Po utworzeniu bazy danych program EF tworzy tabele, które mają takie same nazwy jak DbSet nazwy właściwości. Nazwy właściwości kolekcji są zwykle mnogią. Na przykład Students zamiast Student. Deweloperzy nie zgadzają się, czy nazwy tabel powinny być w liczbie mnogiej, czy nie. W przypadku tych samouczków domyślne zachowanie jest zastępowane przez określenie pojedynczych nazw tabel w pliku DbContext. W tym celu dodaj następujący wyróżniony kod po ostatniej właściwości DbSet.

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

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

Rejestrowanie SchoolContext

ASP.NET Core obejmuje wstrzykiwanie zależności. Usługi, takie jak kontekst bazy danych EF, są rejestrowane za pomocą wstrzykiwania zależności podczas uruchamiania aplikacji. Składniki, które wymagają tych usług, takich jak kontrolery MVC, są udostępniane za pośrednictwem parametrów konstruktora. Kod konstruktora kontrolera, który pobiera wystąpienie kontekstu, jest wyświetlany w dalszej części tego samouczka.

Aby zarejestrować się SchoolContext jako usługa, otwórz plik Startup.csi dodaj wyróżnione wiersze do ConfigureServices metody .

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

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

        public IConfiguration Configuration { get; }

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

            services.AddControllersWithViews();
        }

Nazwa parametry połączenia jest przekazywana do kontekstu przez wywołanie metody w DbContextOptionsBuilder obiekcie. W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje parametry połączenia z appsettings.json pliku.

appsettings.json Otwórz plik i dodaj parametry połączenia, jak pokazano w następującym znaczniku:

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

Dodawanie filtru wyjątku bazy danych

Dodaj AddDatabaseDeveloperPageExceptionFilter element do ConfigureServices , jak pokazano w poniższym kodzie:

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

    services.AddDatabaseDeveloperPageExceptionFilter();

    services.AddControllersWithViews();
}

Zawiera AddDatabaseDeveloperPageExceptionFilter przydatne informacje o błędach w środowisku deweloperów.

SQL Server Express LocalDB

Parametry połączenia określa sql Server LocalDB. LocalDB to uproszczona wersja aparatu bazy danych SQL Server Express i jest przeznaczona do tworzenia aplikacji, a nie do użytku produkcyjnego. Baza danych LocalDB uruchamia się na żądanie i działa w trybie użytkownika, więc nie ma złożonej konfiguracji. Domyślnie baza danych LocalDB tworzy pliki bazy danych .mdf w C:/Users/<user> katalogu.

Inicjowanie bazy danych przy użyciu danych testowych

Program EF tworzy pustą bazę danych. W tej sekcji dodawana jest metoda wywoływana po utworzeniu bazy danych w celu wypełnienia jej danymi testowymi.

Metoda EnsureCreated jest używana do automatycznego tworzenia bazy danych. W późniejszym samouczku zobaczysz, jak obsługiwać zmiany modelu przy użyciu Migracje Code First, aby zmienić schemat bazy danych zamiast usuwać i ponownie tworzyć bazę danych.

W folderze Dane utwórz nową klasę o nazwie przy użyciu DbInitializer 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)
        {
            context.Database.EnsureCreated();

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

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

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

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

Powyższy kod sprawdza, czy baza danych istnieje:

  • Jeśli baza danych nie zostanie znaleziona;
    • Jest on tworzony i ładowany z danymi testowymi. Ładuje dane testowe do tablic, a nie List<T> kolekcji w celu zoptymalizowania wydajności.
  • Jeśli baza danych zostanie znaleziona, nie podejmuje żadnych działań.

Zaktualizuj Program.cs za pomocą następującego kodu:

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

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

            CreateDbIfNotExists(host);

            host.Run();
        }

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

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

Program.cs program wykonuje następujące czynności podczas uruchamiania aplikacji:

  • Pobierz wystąpienie kontekstu bazy danych z kontenera wstrzykiwania zależności.
  • Wywołaj metodę DbInitializer.Initialize .
  • Usuwanie kontekstu po zakończeniu Initialize metody, jak pokazano w poniższym kodzie:
public static void Main(string[] args)
{
     var host = CreateWebHostBuilder(args).Build();

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

    host.Run();
}

Przy pierwszym uruchomieniu aplikacji baza danych jest tworzona i ładowana z danymi testowymi. Za każdym razem, gdy model danych ulegnie zmianie:

  • Usuń bazę danych.
  • Zaktualizuj metodę inicjuj i rozpocznij od nowa przy użyciu nowej bazy danych.

W kolejnych samouczkach baza danych jest modyfikowana po zmianie modelu danych bez usuwania i ponownego tworzenia. W przypadku zmiany modelu danych żadne dane nie zostaną utracone.

Tworzenie kontrolera i widoków

Użyj aparatu tworzenia szkieletów w programie Visual Studio, aby dodać kontroler MVC i widoki, które będą używać programu EF do wykonywania zapytań i zapisywania danych.

Automatyczne tworzenie metod akcji CRUD i widoków jest nazywane tworzeniem szkieletów.

  • W Eksplorator rozwiązań kliknij prawym przyciskiem Controllers myszy folder i wybierz polecenie Dodaj > nowy element szkieletowy.
  • W oknie dialogowym Dodawanie szkieletu:
    • Wybierz kontroler MVC z widokami przy użyciu platformy Entity Framework.
    • Kliknij przycisk Dodaj. Zostanie wyświetlone okno dialogowe Dodawanie kontrolera MVC z widokami przy użyciu programu Entity Framework : Scaffold Student
    • W klasie Model wybierz pozycję Student.
    • W obszarze Klasa kontekstu danych wybierz pozycję SchoolContext.
    • Zaakceptuj domyślną nazwę StudentsController .
    • Kliknij przycisk Dodaj.

Aparat tworzenia szkieletów programu Visual Studio tworzy StudentsController.cs plik i zestaw widoków (*.cshtml plików), które współpracują z kontrolerem.

Zwróć uwagę, że kontroler przyjmuje SchoolContext jako parametr konstruktora.

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

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

ASP.NET Iniekcja zależności Core zajmuje się przekazywaniem wystąpienia SchoolContext do kontrolera. Skonfigurowano to w Startup klasie .

Kontroler zawiera metodę Index akcji, która wyświetla wszystkich uczniów w bazie danych. Metoda pobiera listę uczniów z zestawu jednostek Students, odczytując Students właściwość wystąpienia kontekstu bazy danych:

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

Elementy programowania asynchronicznego w tym kodzie zostały wyjaśnione w dalszej części tego samouczka.

Widok Views/Students/Index.cshtml wyświetla tę listę w tabeli:

@model IEnumerable<ContosoUniversity.Models.Student>

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

<h2>Index</h2>

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

Naciśnij klawisze CTRL+F5, aby uruchomić projekt, lub wybierz polecenie Debuguj > start bez debugowania z menu.

Kliknij kartę Uczniowie, aby wyświetlić dane testowe wstawione przez metodę DbInitializer.Initialize . W zależności od tego, jak wąskie jest okno przeglądarki, w górnej części strony zobaczysz Students link tabulatora lub musisz kliknąć ikonę nawigacji w prawym górnym rogu, aby wyświetlić link.

Contoso University home page narrow

Students Index page

Wyświetlanie bazy danych

Po uruchomieniu aplikacji metoda wywołuje metodę DbInitializer.InitializeEnsureCreated. Ef zobaczyła, że nie ma bazy danych:

  • W związku z tym utworzono bazę danych.
  • Kod Initialize metody wypełnił bazę danych danymi.

Użyj programu SQL Server Eksplorator obiektów (SSOX), aby wyświetlić bazę danych w programie Visual Studio:

  • Wybierz pozycję SQL Server Eksplorator obiektów z menu Widok w programie Visual Studio.
  • W programie SSOX wybierz pozycję (localdb)\MSSQLLocalDB > Databases.
  • Wybierz ContosoUniversity1pozycję , wpis nazwy bazy danych, która znajduje się w parametry połączenia w appsettings.json pliku.
  • Rozwiń węzeł Tabele, aby wyświetlić tabele w bazie danych.

Tables in SSOX

Kliknij prawym przyciskiem myszy tabelę Student i kliknij pozycję Wyświetl dane , aby wyświetlić dane w tabeli.

Student table in SSOX

Pliki *.mdf i *.ldf bazy danych znajdują się w folderze C:\Users\<username> .

Ponieważ EnsureCreated jest wywoływana w metodzie inicjatora uruchamianej podczas uruchamiania aplikacji, możesz:

  • Wprowadź zmianę w Student klasie.
  • Usuń bazę danych.
  • Zatrzymaj, a następnie uruchom aplikację. Baza danych zostanie automatycznie utworzona ponownie, aby dopasować ją do zmiany.

Jeśli na przykład EmailAddress właściwość zostanie dodana do Student klasy, nowa EmailAddress kolumna w ponownie utworzonej tabeli. Widok nie wyświetli nowej EmailAddress właściwości.

Konwencje

Ilość kodu napisanego w celu utworzenia kompletnej bazy danych przez program EF jest minimalna ze względu na użycie konwencji ef:

  • Nazwy DbSet właściwości są używane jako nazwy tabel. W przypadku jednostek, do których nie odwołuje się DbSet właściwość, nazwy klas jednostek są używane jako nazwy tabel.
  • Nazwy właściwości jednostki są używane dla nazw kolumn.
  • Właściwości jednostki o nazwie ID lub classnameID są rozpoznawane jako właściwości PK.
  • Właściwość jest interpretowana jako właściwość FK, jeśli nazwa <właściwości nawigacji nazwa><właściwości PK>. Na przykład StudentID dla Student właściwości nawigacji, ponieważ Student klucz PK jednostki to ID. Właściwości klucza FK mogą być również nazwane <nazwą> właściwości klucza podstawowego. Na przykład ponieważ EnrollmentID klucz Enrollment PK jednostki to EnrollmentID.

Konwencjonalne zachowanie można zastąpić. Na przykład nazwy tabel można jawnie określić, jak pokazano wcześniej w tym samouczku. Nazwy kolumn i dowolną właściwość można ustawić jako klucz PK lub FK.

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 związku z tym kod asynchroniczny umożliwia wydajniejsze wykorzystanie zasobów serwera, a serwer jest włączony do obsługi większej liczby ruchu bez opóźnień.

Kod asynchroniczny wprowadza niewielką ilość narzutów w czasie wykonywania, ale w przypadku małych sytuacji ruch trafień wydajności jest niewielki, podczas gdy w przypadku dużych sytuacji związanych z ruchem potencjalna poprawa wydajności jest znacząca.

W poniższym kodzie , async, Task<T>awaiti ToListAsync wykonaj kod asynchronicznie.

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
  • Słowo async kluczowe nakazuje kompilatorowi generowanie wywołań zwrotnych dla części treści metody i automatyczne tworzenie Task<IActionResult> zwracanego obiektu.
  • Zwracany typ Task<IActionResult> reprezentuje bieżącą pracę z wynikiem typu IActionResult.
  • 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 wersja ToList metody rozszerzenia.

Niektóre kwestie, o których należy pamiętać podczas pisania kodu asynchronicznego korzystającego z programu EF:

  • Tylko instrukcje, które powodują wysyłanie zapytań lub poleceń do bazy danych, są wykonywane asynchronicznie. Dotyczy to na przykład ToListAsync, i SingleOrDefaultAsyncSaveChangesAsync. Nie zawiera na przykład instrukcji, które po prostu zmieniają IQueryableelement , na przykład var students = context.Students.Where(s => s.LastName == "Davolio").
  • Kontekst EF nie jest bezpieczny wątkiem: nie próbuj wykonywać wielu operacji równolegle. Podczas wywoływania dowolnej metody asynchronicznej EF zawsze należy użyć słowa kluczowego await .
  • Aby skorzystać z zalet wydajności kodu asynchronicznego, upewnij się, że wszystkie pakiety bibliotek używane również używają asynchronicznego, jeśli wywołują jakiekolwiek metody EF, które powodują wysyłanie zapytań do bazy danych.

Aby uzyskać więcej informacji na temat programowania asynchronicznego na platformie .NET, zobacz Async Overview (Omówienie asynchroniczne).

Ogranicz pobrane jednostki

Zobacz Zagadnienia dotyczące wydajności, aby uzyskać informacje na temat ograniczania liczby jednostek zwracanych z zapytania.

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 wł. JSinstrukcje 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.

Przejdź do następnego samouczka, aby dowiedzieć się, jak wykonywać podstawowe operacje CRUD (tworzenie, odczytywanie, aktualizowanie, usuwanie).

W tym samouczku przedstawiono model ASP.NET Core MVC i program Entity Framework Core z kontrolerami i widokami. Strony Razor to alternatywny model programowania. W przypadku nowego projektu programowania zalecamy używanie stron Razor w zamiast modelu MVC z kontrolerami i widokami. Zobacz wersję tego samouczka dla stron Razor. Każdy z tych samouczków obejmuje pewne materiały, których nie ma w drugim:

Niektóre elementy tego samouczka modelu MVC, które nie są dostępne w przypadku stron Razor:

  • Implementowanie dziedziczenia w modelu danych
  • Wykonywanie pierwotnych zapytań SQL
  • Używanie dynamicznych zapytań LINQ w celu uproszczenia kodu

Niektóre elementy samouczka dotyczącego stron Razor, których nie ma w tym samouczku:

  • Ładowanie powiązanych danych za pomocą metody Select
  • Najlepsze rozwiązania dotyczące platformy EF.

Przykładowa aplikacja internetowa Contoso University pokazuje, jak tworzyć aplikacje internetowe platformy ASP.NET Core 2.2 MVC przy użyciu platformy Entity Framework (EF) Core 2.2 i programu Visual Studio 2019.

Ten samouczek nie został zaktualizowany dla ASP.NET Core 3.1. Została ona zaktualizowana dla ASP.NET Core 5.0.

Przykładowa aplikacja to witryna internetowa fikcyjnego uniwersytetu Contoso. Obejmuje ona funkcje, takie jak wstęp dla uczniów, tworzenie kursów i zadania instruktora. Jest to pierwszy z serii samouczków, które wyjaśniają, jak utworzyć przykładową aplikację Contoso University od podstaw.

Wymagania wstępne

Rozwiązywanie problemów

Jeśli napotkasz problem, którego nie możesz rozwiązać, zazwyczaj możesz znaleźć rozwiązanie, porównując kod z ukończonym projektem. Aby uzyskać listę typowych błędów i sposób ich rozwiązywania, zobacz sekcję Rozwiązywanie problemów z ostatnim samouczkiem z serii. Jeśli nie znajdziesz tam potrzebnych informacji, możesz opublikować pytanie, aby StackOverflow.com dla platformy ASP.NET Core lub EF Core.

Napiwek

Jest to seria 10 samouczków, z których każda opiera się na tym, co zostało wykonane we wcześniejszych samouczkach. Rozważ zapisanie kopii projektu po zakończeniu każdego pomyślnego ukończenia samouczka. Następnie, jeśli wystąpią problemy, możesz zacząć od poprzedniego samouczka zamiast wracać do początku całej serii.

Aplikacja internetowa Contoso University

Aplikacja, którą utworzysz w tych samouczkach, jest prostą witryną internetową uniwersytetu.

Użytkownicy mogą wyświetlać i aktualizować informacje o uczniach, kursach i instruktorach. Oto kilka ekranów, które utworzysz.

Students Index page

Students Edit page

Tworzenie aplikacji internetowej

  • Otwórz program Visual Studio.

  • W menu Plik wybierz pozycję Nowy > projekt.

  • W okienku po lewej stronie wybierz pozycję Zainstalowano sieć > Web visual C#>.

  • Wybierz szablon projektu ASP.NET Core Web Application.

  • Wprowadź nazwę ContosoUniversity i kliknij przycisk OK.

    New Project dialog

  • Poczekaj na wyświetlenie okna dialogowego Nowa aplikacja internetowa ASP.NET Core.

  • Wybierz pozycję .NET Core, ASP.NET Core 2.2 i szablon Aplikacja internetowa (Model-View-Controller).

  • Upewnij się, że ustawienie Uwierzytelnianie ma wartość Brak uwierzytelniania.

  • Wybierz OK

    New ASP.NET Core Project dialog

Konfigurowanie stylu witryny

Kilka prostych zmian spowoduje skonfigurowanie menu witryny, układu i strony głównej.

Otwórz Views/Shared/_Layout.cshtml plik i wprowadź następujące zmiany:

  • Zmień każde wystąpienie "ContosoUniversity" na "Contoso University". Istnieją trzy wystąpienia.

  • Dodaj pozycje menu Informacje, Uczniowie, Kursy, Instruktorzy i Działy oraz usuń Privacy wpis menu.

Zmiany są wyróżnione.

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

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

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

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

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

W Views/Home/Index.cshtmlpliku zastąp zawartość pliku następującym kodem, aby zastąpić tekst ASP.NET i MVC tekstem o tej aplikacji:

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

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

Naciśnij klawisze CTRL+F5, aby uruchomić projekt, lub wybierz polecenie Debuguj > start bez debugowania z menu. Zostanie wyświetlona strona główna z kartami stron, które zostaną utworzone w tych samouczkach.

Contoso University home page

Informacje o EF Core pakietach NuGet

Aby dodać EF Core obsługę projektu, zainstaluj dostawcę bazy danych, którego chcesz użyć. W tym samouczku jest używany program SQL Server, a pakiet dostawcy to Microsoft.EntityFrameworkCore.SqlServer. Ten pakiet jest zawarty w Microsoft.AspNetCore.App metapakiecie, więc nie trzeba odwoływać się do pakietu.

Pakiet EF SQL Server i jego zależności (Microsoft.EntityFrameworkCore i Microsoft.EntityFrameworkCore.Relational) zapewniają obsługę środowiska uruchomieniowego dla programu EF. Później dodasz pakiet narzędzi w samouczku Migracje .

Aby uzyskać informacje o innych dostawcach baz danych dostępnych dla platformy Entity Framework Core, zobacz Dostawcy baz danych.

Tworzenie modelu danych

Następnie utworzysz klasy jednostek dla aplikacji Contoso University. Zaczniesz od następujących trzech jednostek.

Course-Enrollment-Student data model diagram

Istnieje relacja jeden do wielu między jednostkami Student i Enrollment , a istnieje relacja jeden do wielu między jednostkami Course i Enrollment . Innymi słowy, student może być zarejestrowany w dowolnej liczbie kursów, a kurs może mieć dowolną liczbę uczniów zarejestrowanych w nim.

W poniższych sekcjach utworzysz klasę dla każdej z tych jednostek.

Jednostka Student

Student entity diagram

W folderze Models utwórz plik klasy o nazwie Student.cs i zastąp kod szablonu następującym kodem.

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 stanie się kolumną klucza podstawowego tabeli bazy danych, która odpowiada tej klasie. Domyślnie platforma Entity Framework interpretuje właściwość o nazwie ID lub classnameID jako klucz podstawowy.

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 entity obiektu będzie przechowywać wszystkie Enrollment jednostki powiązane z tą Student jednostką. Innymi słowy, jeśli Student wiersz w bazie danych zawiera dwa powiązane Enrollment wiersze (wiersze zawierające podstawową wartość klucza ucznia w kolumnie klucza obcego StudentID), Student właściwość nawigacji tej jednostki Enrollments będzie zawierać te dwie Enrollment jednostki.

Jeśli właściwość nawigacji może zawierać wiele jednostek (jak w relacjach wiele do wielu lub jeden do wielu), jej typ musi być listą, w której można dodawać, usuwać i aktualizować wpisy, takie jak ICollection<T>. Można określić ICollection<T> lub typ, taki jak List<T> lub HashSet<T>. Jeśli określisz ICollection<T>wartość , program EF domyślnie tworzy HashSet<T> kolekcję.

Jednostka Rejestracja

Enrollment entity diagram

W folderze Models utwórz Enrollment.cs i zastąp istniejący kod następującym kodem:

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ść będzie kluczem podstawowym. Ta EnrollmentID jednostka używa classnameID wzorca zamiast ID samego siebie, jak pokazano w jednostce Student . Zazwyczaj należy wybrać jeden wzorzec i używać go w całym modelu danych. W tym miejscu odmiana ilustruje, że można użyć dowolnego wzorca. W późniejszym samouczku zobaczysz, jak używanie identyfikatora bez nazwy klasy ułatwia implementowanie dziedziczenia w 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. Klasa, która ma wartość 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ść może przechowywać tylko jedną Student jednostkę (w przeciwieństwie do Student.Enrollments właściwości nawigacji, która może zawierać wiele Enrollment jednostek).

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 .

Program Entity Framework interpretuje właściwość jako właściwość klucza obcego, jeśli jest ona nazwana <navigation property name><primary key property name> (na przykład dla Student właściwości nawigacji, StudentID ponieważ Student klucz podstawowy jednostki to ID). Właściwości klucza obcego można również nazwać po prostu <primary key property name> (na przykład CourseID ponieważ Course klucz podstawowy jednostki to CourseID).

Jednostka Course

Course entity diagram

W folderze Models utwórz Course.cs i zastąp istniejący kod następującym kodem:

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.

Więcej informacji na temat atrybutu DatabaseGenerated znajdziesz w dalszej części tego samouczka w tej serii. Zasadniczo ten atrybut umożliwia wprowadzenie klucza podstawowego dla kursu zamiast generowania bazy danych.

Tworzenie kontekstu bazy danych

Główną klasą, która koordynuje funkcje programu Entity Framework dla danego modelu danych, jest klasa kontekstu bazy danych. Ta klasa jest tworzona przez wyprowadzenie z Microsoft.EntityFrameworkCore.DbContext klasy . W kodzie określisz, które jednostki są uwzględnione w modelu danych. Można również dostosować pewne zachowanie platformy Entity Framework. W tym projekcie klasa nosi nazwę SchoolContext.

W folderze projektu utwórz folder o nazwie Dane.

W folderze Dane utwórz nowy plik klasy o nazwie SchoolContext.csi zastąp kod szablonu następującym kodem:

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

Ten kod tworzy DbSet właściwość dla każdego zestawu jednostek. W terminologii platformy Entity Framework zestaw jednostek zwykle odpowiada tabeli bazy danych, a jednostka odpowiada wierszowi w tabeli.

Można pominąć instrukcje DbSet<Enrollment> i DbSet<Course> i działałoby to samo. Program Entity Framework uwzględnia je niejawnie, ponieważ Student jednostka odwołuje się do Enrollment jednostki, a Enrollment jednostka odwołuje się do Course jednostki.

Po utworzeniu bazy danych program EF tworzy tabele, które mają takie same nazwy jak DbSet nazwy właściwości. Nazwy właściwości kolekcji są zwykle mnogią (Uczniowie, a nie Student), ale deweloperzy nie zgadzają się, czy nazwy tabel powinny być w liczbie mnogiej, czy nie. W tych samouczkach zastąpisz domyślne zachowanie, określając pojedyncze nazwy tabel w obiekcie DbContext. W tym celu dodaj następujący wyróżniony kod po ostatniej właściwości DbSet.

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

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

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

Skompiluj projekt jako sprawdzenie błędów kompilatora.

Rejestrowanie elementu SchoolContext

ASP.NET Core domyślnie implementuje wstrzykiwanie zależności. Usługi (takie jak kontekst bazy danych EF) są rejestrowane za pomocą wstrzykiwania zależności podczas uruchamiania aplikacji. Składniki, które wymagają tych usług (takich jak kontrolery MVC), są udostępniane za pośrednictwem parametrów konstruktora. W dalszej części tego samouczka zobaczysz kod konstruktora kontrolera, który pobiera wystąpienie kontekstu.

Aby zarejestrować się SchoolContext jako usługa, otwórz plik Startup.csi dodaj wyróżnione wiersze do ConfigureServices metody .

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

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

    services.AddMvc();
}

Nazwa parametry połączenia jest przekazywana do kontekstu przez wywołanie metody w DbContextOptionsBuilder obiekcie. W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje parametry połączenia z appsettings.json pliku.

Dodaj using instrukcje dla ContosoUniversity.Data przestrzeni nazw i Microsoft.EntityFrameworkCore , a następnie skompiluj projekt.

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

appsettings.json Otwórz plik i dodaj parametry połączenia, jak pokazano w poniższym przykładzie.

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

SQL Server Express LocalDB

Parametry połączenia określa bazę danych SQL Server LocalDB. LocalDB to uproszczona wersja aparatu bazy danych SQL Server Express i jest przeznaczona do tworzenia aplikacji, a nie do użytku produkcyjnego. Baza danych LocalDB uruchamia się na żądanie i działa w trybie użytkownika, więc nie ma złożonej konfiguracji. Domyślnie baza danych LocalDB tworzy pliki bazy danych .mdf w C:/Users/<user> katalogu.

Inicjowanie bazy danych przy użyciu danych testowych

Platforma Entity Framework utworzy pustą bazę danych. W tej sekcji napiszesz metodę wywoływaną po utworzeniu bazy danych, aby wypełnić ją danymi testowymi.

W tym miejscu użyjesz EnsureCreated metody , aby automatycznie utworzyć bazę danych. W późniejszym samouczku dowiesz się, jak obsługiwać zmiany modelu przy użyciu Migracje Code First, aby zmienić schemat bazy danych zamiast usuwać i ponownie tworzyć bazę danych.

W folderze Dane utwórz nowy plik klasy o nazwie DbInitializer.cs i zastąp kod szablonu następującym kodem, co powoduje utworzenie bazy danych w razie potrzeby i załadowanie danych testowych do nowej bazy danych.

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

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

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

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

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

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

Kod sprawdza, czy w bazie danych znajdują się jakieś uczniowie, a jeśli nie, zakłada, że baza danych jest nowa i musi zostać rozstawiona z danymi testowymi. Ładuje dane testowe do tablic, a nie List<T> kolekcji w celu zoptymalizowania wydajności.

W Program.cspliku zmodyfikuj metodę , Main aby wykonać następujące czynności podczas uruchamiania aplikacji:

  • Pobierz wystąpienie kontekstu bazy danych z kontenera wstrzykiwania zależności.
  • Wywołaj metodę seed, przekazując do niej kontekst.
  • Po zakończeniu metody inicjowania należy usunąć kontekst.
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

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

            CreateDbIfNotExists(host);

            host.Run();
        }

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

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

Przy pierwszym uruchomieniu aplikacji baza danych zostanie utworzona i rozstawiona z danymi testowymi. Za każdym razem, gdy zmienisz model danych:

  • Usuń bazę danych.
  • Zaktualizuj metodę inicjuj i rozpocznij od nowa nową bazę danych w taki sam sposób.

W kolejnych samouczkach dowiesz się, jak zmodyfikować bazę danych, gdy model danych ulegnie zmianie, bez usuwania i ponownego tworzenia bazy danych.

Tworzenie kontrolera i widoków

W tej sekcji aparat tworzenia szkieletów w programie Visual Studio służy do dodawania kontrolera MVC i widoków, które będą używać programu EF do wykonywania zapytań i zapisywania danych.

Automatyczne tworzenie metod akcji CRUD i widoków jest nazywane tworzeniem szkieletów. Tworzenie szkieletów różni się od generowania kodu w tym, że szkielet kodu jest punktem wyjścia, który można zmodyfikować zgodnie z własnymi wymaganiami, podczas gdy zwykle nie modyfikuje się wygenerowanego kodu. Gdy konieczne jest dostosowanie wygenerowanego kodu, należy użyć klas częściowych lub ponownie wygenerować kod po zmianie.

  • Kliknij prawym przyciskiem myszy folder Controllers w Eksplorator rozwiązań i wybierz polecenie Dodaj > nowy element szkieletowy.
  • W oknie dialogowym Dodawanie szkieletu:
    • Wybierz kontroler MVC z widokami przy użyciu platformy Entity Framework.
    • Kliknij przycisk Dodaj. Zostanie wyświetlone okno dialogowe Dodawanie kontrolera MVC z widokami przy użyciu programu Entity Framework : Scaffold Student
    • W obszarze Klasa modelu wybierz pozycję Student.
    • W obszarze Klasa kontekstu danych wybierz pozycję SchoolContext.
    • Zaakceptuj domyślną nazwę StudentsController .
    • Kliknij przycisk Dodaj.

Aparat tworzenia szkieletów programu Visual Studio tworzy StudentsController.cs plik i zestaw widoków (.cshtml plików), które współpracują z kontrolerem.

Zwróć uwagę, że kontroler przyjmuje SchoolContext jako parametr konstruktora.

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

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

ASP.NET Iniekcja zależności Core zajmuje się przekazywaniem wystąpienia SchoolContext do kontrolera. To zostało skonfigurowane w Startup.cs pliku.

Kontroler zawiera metodę Index akcji, która wyświetla wszystkich uczniów w bazie danych. Metoda pobiera listę uczniów z zestawu jednostek Students, odczytując Students właściwość wystąpienia kontekstu bazy danych:

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

W dalszej części tego samouczka poznasz elementy programowania asynchronicznego.

Widok Views/Students/Index.cshtml wyświetla tę listę w tabeli:

@model IEnumerable<ContosoUniversity.Models.Student>

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

<h2>Index</h2>

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

Naciśnij klawisze CTRL+F5, aby uruchomić projekt, lub wybierz polecenie Debuguj > start bez debugowania z menu.

Kliknij kartę Uczniowie, aby wyświetlić dane testowe wstawione przez metodę DbInitializer.Initialize . W zależności od tego, jak wąskie jest okno przeglądarki, w górnej części strony zobaczysz Students link tabulatora lub musisz kliknąć ikonę nawigacji w prawym górnym rogu, aby wyświetlić link.

Contoso University home page narrow

Students Index page

Wyświetlanie bazy danych

Po uruchomieniu aplikacji metoda wywołuje metodę DbInitializer.InitializeEnsureCreated. Program EF widział, że nie ma bazy danych i dlatego utworzył ją, a następnie pozostałą część Initialize kodu metody wypełniła bazę danych danymi. Aby wyświetlić bazę danych w programie Visual Studio, możesz użyć programu SQL Server Eksplorator obiektów (SSOX).

Zamknij okno przeglądarki.

Jeśli okno SSOX nie jest jeszcze otwarte, wybierz je z menu Widok w programie Visual Studio.

W programie SSOX kliknij pozycję (localdb)\MSSQLLocalDB > Databases, a następnie kliknij wpis nazwy bazy danych, która znajduje się w parametry połączenia w appsettings.json pliku.

Rozwiń węzeł Tabele, aby wyświetlić tabele w bazie danych.

Tables in SSOX

Kliknij prawym przyciskiem myszy tabelę Student i kliknij pozycję Wyświetl dane , aby wyświetlić utworzone kolumny i wiersze wstawione do tabeli.

Student table in SSOX

Pliki bazy danych .mdf i ldf znajdują się w folderze C:\Users\<username> .

Ponieważ wywołujesz EnsureCreated metodę inicjatora uruchamianą podczas uruchamiania aplikacji, możesz teraz wprowadzić zmianę Student w klasie, usunąć bazę danych, ponownie uruchomić aplikację, a baza danych zostanie automatycznie utworzona ponownie, aby dopasować ją do zmiany. Jeśli na przykład dodasz EmailAddress właściwość do Student klasy, zobaczysz nową EmailAddress kolumnę w ponownie utworzonej tabeli.

Konwencje

Ilość kodu, który trzeba było napisać, aby program Entity Framework mógł utworzyć pełną bazę danych, jest minimalny ze względu na użycie konwencji lub założeń, które wykonuje program Entity Framework.

  • Nazwy DbSet właściwości są używane jako nazwy tabel. W przypadku jednostek, do których nie odwołuje się DbSet właściwość, nazwy klas jednostek są używane jako nazwy tabel.
  • Nazwy właściwości jednostki są używane dla nazw kolumn.
  • Właściwości jednostki o nazwie ID lub classnameID są rozpoznawane jako właściwości klucza podstawowego.
  • Właściwość jest interpretowana jako właściwość klucza obcego, jeśli nosi nazwę właściwości nawigacji nazwa><właściwości klucza podstawowego (na przykład dla Student właściwości nawigacji, StudentID ponieważ Student klucz podstawowy> jednostki to ID).< Właściwości klucza obcego można również nazwać po prostu <nazwą> właściwości klucza podstawowego (na przykład ponieważ EnrollmentIDEnrollment klucz podstawowy jednostki to ).EnrollmentID

Konwencjonalne zachowanie można zastąpić. Można na przykład jawnie określić nazwy tabel, jak pokazano wcześniej w tym samouczku. Możesz również ustawić nazwy kolumn i ustawić dowolną właściwość jako klucz podstawowy lub klucz obcy, jak pokazano w dalszej części tego samouczka .

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 związku z tym kod asynchroniczny umożliwia wydajniejsze wykorzystanie zasobów serwera, a serwer jest włączony do obsługi większej liczby ruchu bez opóźnień.

Kod asynchroniczny wprowadza niewielką ilość narzutów w czasie wykonywania, ale w przypadku małych sytuacji ruch trafień wydajności jest niewielki, podczas gdy w przypadku dużych sytuacji związanych z ruchem potencjalna poprawa wydajności jest znacząca.

W poniższym kodzie słowo kluczowe, wartość zwracana, Task<T>await słowo kluczowe i ToListAsync metoda sprawiają, async że kod jest wykonywany asynchronicznie.

public async Task<IActionResult> Index()
{
    return View(await _context.Students.ToListAsync());
}
  • Słowo async kluczowe nakazuje kompilatorowi generowanie wywołań zwrotnych dla części treści metody i automatyczne tworzenie Task<IActionResult> zwracanego obiektu.
  • Zwracany typ Task<IActionResult> reprezentuje bieżącą pracę z wynikiem typu IActionResult.
  • 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 wersja ToList metody rozszerzenia.

Niektóre kwestie, o których należy pamiętać podczas pisania kodu asynchronicznego korzystającego z programu Entity Framework:

  • Tylko instrukcje, które powodują wysyłanie zapytań lub poleceń do bazy danych, są wykonywane asynchronicznie. Dotyczy to na przykład ToListAsync, i SingleOrDefaultAsyncSaveChangesAsync. Nie zawiera na przykład instrukcji, które po prostu zmieniają IQueryableelement , na przykład var students = context.Students.Where(s => s.LastName == "Davolio").
  • Kontekst EF nie jest bezpieczny wątkiem: nie próbuj wykonywać wielu operacji równolegle. Podczas wywoływania dowolnej metody asynchronicznej EF zawsze należy użyć słowa kluczowego await .
  • Jeśli chcesz skorzystać z zalet wydajności kodu asynchronicznego, upewnij się, że wszystkie używane pakiety bibliotek (takie jak na potrzeby stronicowania), należy również użyć asynchronicznego, jeśli wywołują one dowolne metody programu Entity Framework, które powodują wysyłanie zapytań do bazy danych.

Aby uzyskać więcej informacji na temat programowania asynchronicznego na platformie .NET, zobacz Async Overview (Omówienie asynchroniczne).

Następne kroki

Przejdź do następnego samouczka, aby dowiedzieć się, jak wykonywać podstawowe operacje CRUD (tworzenie, odczytywanie, aktualizowanie, usuwanie).