Część 4. Dodawanie modelu do aplikacji MVC platformy ASP.NET Core

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Przez Rick Anderson i Jon P Smith.

W tym samouczku klasy są dodawane do zarządzania filmami w bazie danych. Te klasy są częścią "odel" aplikacji MVC.

Te klasy modeli są używane z programem Entity Framework Core (EF Core) do pracy z bazą danych. EF Core to struktura mapowania relacyjnego (ORM, object-relational mapping), która upraszcza kod dostępu do danych, który trzeba napisać.

Utworzone klasy modeli są nazywane klasami POCO z Plain Old CLR Objects. Klasy POCO nie mają żadnej zależności od EF Coreklasy . Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku klasy modeli są tworzone najpierw i EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder >Models Dodaj>klasę. Nazwij plik Movie.cs.

Models/Movie.cs Zaktualizuj plik przy użyciu następującego kodu:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    public decimal Price { get; set; }
}

Klasa Movie zawiera Id pole wymagane przez bazę danych dla klucza podstawowego.

Atrybut DataType on ReleaseDate określa typ danych (Date). Za pomocą tego atrybutu:

  • Użytkownik nie musi wprowadzać informacji o godzinie w polu daty.
  • Wyświetlana jest tylko data, a nie informacje o godzinie.

Adnotacje danych zostały omówione w późniejszym samouczku.

Znak zapytania po string wskazuje, że właściwość jest dopuszczana do wartości null. Aby uzyskać więcej informacji, zobacz Typy referencyjne dopuszczane do wartości null.

Dodawanie pakietów NuGet

Program Visual Studio automatycznie instaluje wymagane pakiety.

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

Strony filmów szkieletowych

Narzędzie do tworzenia szkieletów umożliwia tworzenie Createstron , Read, Updatei Delete (CRUD) dla modelu filmu.

W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Controllers i wybierz polecenie Dodaj > nowy element szkieletowy.

widok powyższego kroku

W oknie dialogowym Dodawanie nowego elementu szkieletu:

  • W okienku po lewej stronie wybierz pozycję Zainstalowane>wspólne>MVC.
  • Wybierz pozycję Kontroler MVC z widokami przy użyciu platformy Entity Framework.
  • Wybierz Dodaj.

Okno dialogowe Dodawanie szkieletu

Ukończ okno dialogowe Dodawanie kontrolera MVC z widokami przy użyciu okna dialogowego Entity Framework:

  • Z listy rozwijanej Klasa modelu wybierz pozycję Movie (MvcFilm.Models).
  • W wierszu Klasy kontekstu danych wybierz + znak (plus).
    • W oknie dialogowym Dodawanie kontekstu danych jest generowana nazwa klasy MvcFilm.Data.MvcTextContext.
    • Wybierz Dodaj.
  • Z listy rozwijanej Dostawca bazy danych wybierz pozycję SQL Server.
  • Widoki i nazwa kontrolera: zachowaj wartość domyślną.
  • Wybierz Dodaj.

Dodaj kontekst danych zachowaj wartości domyślne

Jeśli zostanie wyświetlony komunikat o błędzie, wybierz pozycję Dodaj po raz drugi, aby spróbować ponownie.

Tworzenie szkieletu dodaje następujące pakiety:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Tworzenie szkieletu powoduje utworzenie następujących elementów:

  • Kontroler filmów: Controllers/MoviesController.cs
  • Razor wyświetl pliki dla stron Tworzenie, Usuwanie, Szczegóły, Edytowanie i Indeks : Views/Movies/*.cshtml
  • Klasa kontekstu bazy danych: Data/MvcMovieContext.cs

Tworzenie szkieletu aktualizuje następujące elementy:

  • Wstawia wymagane odwołania do pakietu w MvcMovie.csproj pliku projektu.
  • Rejestruje kontekst bazy danych w Program.cs pliku.
  • Dodaje parametry połączenia bazy danych do appsettings.json pliku.

Automatyczne tworzenie tych plików i aktualizacji plików jest nazywane tworzeniem szkieletów.

Nie można jeszcze używać stron szkieletowych, ponieważ baza danych nie istnieje. Uruchomienie aplikacji i wybranie linku Aplikacja filmowa powoduje otwarcie bazy danych lub brak takiej tabeli: komunikat o błędzie Filmu .

Skompiluj aplikację, aby sprawdzić, czy nie ma żadnych błędów.

Migracja początkowa

EF CoreUżyj funkcji Migracje, aby utworzyć bazę danych. Migracje to zestaw narzędzi, które tworzą i aktualizują bazę danych w celu dopasowania ich do modelu danych.

Z menu Narzędzia wybierz pozycję NuGet Menedżer pakietów> Menedżer pakietów Konsola .

W konsoli Menedżer pakietów (PMC) wprowadź następujące polecenia:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: generuje Migrations/{timestamp}_InitialCreate.cs plik migracji. Argumentem InitialCreate jest nazwa migracji. Można użyć dowolnej nazwy, ale zgodnie z konwencją wybrana jest nazwa opisującą migrację. Ponieważ jest to pierwsza migracja, wygenerowana klasa zawiera kod umożliwiający utworzenie schematu bazy danych. Schemat bazy danych jest oparty na modelu określonym w MvcMovieContext klasie.

  • Update-Database: Aktualizacje bazę danych do najnowszej migracji, która została utworzona przez poprzednie polecenie. To polecenie uruchamia metodę Up w Migrations/{time-stamp}_InitialCreate.cs pliku, która tworzy bazę danych.

Polecenie Update-Database generuje następujące ostrzeżenie:

Nie określono typu magazynu dla właściwości dziesiętnej "Price" w typie jednostki "Movie". Spowoduje to dyskretne obcięcie wartości, jeśli nie mieszczą się w domyślnej precyzji i skali. Jawnie określ typ kolumny programu SQL Server, który może pomieścić wszystkie wartości w elemencie "OnModelCreating" przy użyciu polecenia "HasColumnType", określić precyzję i skalę przy użyciu polecenia "HasPrecision" lub skonfigurować konwerter wartości przy użyciu polecenia "HasConversion".

Zignoruj powyższe ostrzeżenie. Jest on naprawiony w późniejszym samouczku.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Coreprogramu , zobacz EF Core dokumentacja narzędzi — PMC w programie Visual Studio.

Testowanie aplikacji

Uruchom aplikację i wybierz link Aplikacja filmowa.

Jeśli wystąpi wyjątek podobny do poniższego, być może pominięto Update-Database polecenie w kroku migracji:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Uwaga

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i w formatach dat innych niż angielskie stany USA, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz ten problem z usługą GitHub.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W przypadku EF Coreprogramu dostęp do danych jest wykonywany przy użyciu modelu. Model składa się z klas jednostek i obiektu kontekstu, który reprezentuje sesję z bazą danych. Obiekt kontekstu umożliwia wykonywanie zapytań i zapisywanie danych. Kontekst bazy danych pochodzi z elementu Microsoft.EntityFrameworkCore.DbContext i określa jednostki do uwzględnienia w modelu danych.

Tworzenie szkieletu Data/MvcMovieContext.cs powoduje utworzenie klasy kontekstu bazy danych:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

Powyższy kod tworzy właściwość DbSet<Movie> reprezentującą filmy w bazie danych.

Wstrzykiwanie zależności

ASP.NET Core jest kompilowany przy użyciu wstrzykiwania zależności (DI). Usługi, takie jak kontekst bazy danych, są rejestrowane w usłudze DI w systemie Program.cs. Te usługi są udostępniane składnikom, które wymagają ich za pośrednictwem parametrów konstruktora.

Controllers/MoviesController.cs W pliku konstruktor używa wstrzykiwania zależności, aby wstrzyknąć MvcMovieContext kontekst bazy danych do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

Tworzenie szkieletu wygenerowało następujący wyróżniony kod w pliku Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));

System konfiguracji ASP.NET Core odczytuje bazę danych "MvcTextContext" parametry połączenia.

Badanie wygenerowanej bazy danych parametry połączenia

Tworzenie szkieletu dodało parametry połączenia do appsettings.json pliku:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Data Source=MvcMovieContext-ea7a4069-f366-4742-bd1c-3f753a804ce1.db"
  }
}

W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje ConnectionString klucz z appsettings.json pliku.

Klasa InitialCreate

Migrations/{timestamp}_InitialCreate.cs Sprawdź plik migracji:

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

Powyższy kod:

  • InitialCreate.Up Tworzy tabelę Movie i konfiguruje Id jako klucz podstawowy.
  • InitialCreate.Down Przywraca zmiany schematu wprowadzone przez migrację Up .

Wstrzykiwanie zależności w kontrolerze

Controllers/MoviesController.cs Otwórz plik i sprawdź konstruktor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktor używa wstrzykiwania zależności do wstrzykiwania kontekstu bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

Przetestuj stronę Tworzenie . Wprowadź i prześlij dane.

Przetestuj strony Edytuj, Szczegóły i Usuń .

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku przy użyciu słownika ViewData . Słownik ViewData jest obiektem dynamicznym, który zapewnia wygodny, opóźniony sposób przekazywania informacji do widoku.

MvC umożliwia przekazywanie silnie typiowanych obiektów modelu do widoku. To silnie typizowane podejście umożliwia sprawdzanie kodu czasu kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowanego modelu w MoviesController klasie i widokach.

Sprawdź wygenerowaną Details metodę w Controllers/MoviesController.cs pliku:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametr id jest zwykle przekazywany jako dane trasy. Na przykład https://localhost:5001/movies/details/1 zestawy:

  • Kontroler kontrolera movies , pierwszy segment adresu URL.
  • Akcja na details, drugi segment adresu URL.
  • Od id 1 do ostatniego segmentu adresu URL.

Element id można przekazać za pomocą ciągu zapytania, jak w poniższym przykładzie:

https://localhost:5001/movies/details?id=1

Parametr id jest definiowany jako typ dopuszczalny do wartości null (int?) w przypadkach, gdy wartość nie jest podana id .

Wyrażenie lambda jest przekazywane do FirstOrDefaultAsync metody , aby wybrać jednostki filmu zgodne z danymi trasy lub wartością ciągu zapytania.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Jeśli zostanie znaleziony film, wystąpienie Movie modelu zostanie przekazane do Details widoku:

return View(movie);

Sprawdź zawartość Views/Movies/Details.cshtml pliku:

@model MvcMovie.Models.Movie

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

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instrukcja @model w górnej części pliku widoku określa typ obiektu, którego oczekuje widok. Po utworzeniu kontrolera filmu dołączono następującą @model instrukcję:

@model MvcMovie.Models.Movie

Ta @model dyrektywa umożliwia dostęp do filmu przekazanego przez kontroler do widoku. Obiekt Model jest silnie typizowane. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor pomocników HTML z DisplayFor silnie typiowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok i metodę Index.cshtmlIndex w kontrolerze Filmy. Zwróć uwagę, że kod tworzy List obiekt, gdy wywołuje metodę View . Kod przekazuje tę Movies listę z Index metody akcji do widoku:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Kod zwraca szczegóły problemu, jeśli Movie właściwość kontekstu danych ma wartość null.

Po utworzeniu kontrolera filmów szkielet zawiera następującą @model instrukcję w górnej Index.cshtml części pliku:

@model IEnumerable<MvcMovie.Models.Movie>

Dyrektywa @model umożliwia dostęp do listy filmów przekazywanych przez kontroler do widoku przy użyciu silnie typizowanego Model obiektu. Na przykład w Index.cshtml widoku kod przechodzi przez filmy za pomocą foreach instrukcji na silnie typizowanego Model obiektu:

@model IEnumerable<MvcMovie.Models.Movie>

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

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </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>

Model Ponieważ obiekt jest silnie typowany jako IEnumerable<Movie> obiekt, każdy element w pętli jest wpisywany jako Movie. Między innymi kompilator weryfikuje typy używane w kodzie.

Dodatkowe zasoby

W tym samouczku klasy są dodawane do zarządzania filmami w bazie danych. Te klasy są częścią "odel" aplikacji MVC.

Te klasy modeli są używane z programem Entity Framework Core (EF Core) do pracy z bazą danych. EF Core to struktura mapowania relacyjnego (ORM, object-relational mapping), która upraszcza kod dostępu do danych, który trzeba napisać.

Utworzone klasy modeli są nazywane klasami POCO z Plain Old CLR Objects. Klasy POCO nie mają żadnej zależności od EF Coreklasy . Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku klasy modeli są tworzone najpierw i EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder >Models Dodaj>klasę. Nazwij plik Movie.cs.

Models/Movie.cs Zaktualizuj plik przy użyciu następującego kodu:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    public string? Title { get; set; }
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    public string? Genre { get; set; }
    public decimal Price { get; set; }
}

Klasa Movie zawiera Id pole wymagane przez bazę danych dla klucza podstawowego.

Atrybut DataType on ReleaseDate określa typ danych (Date). Za pomocą tego atrybutu:

  • Użytkownik nie musi wprowadzać informacji o godzinie w polu daty.
  • Wyświetlana jest tylko data, a nie informacje o godzinie.

Adnotacje danych zostały omówione w późniejszym samouczku.

Znak zapytania po string wskazuje, że właściwość jest dopuszczana do wartości null. Aby uzyskać więcej informacji, zobacz Typy referencyjne dopuszczane do wartości null.

Dodawanie pakietów NuGet

Program Visual Studio automatycznie instaluje wymagane pakiety.

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

Strony filmów szkieletowych

Narzędzie do tworzenia szkieletów umożliwia tworzenie Createstron , Read, Updatei Delete (CRUD) dla modelu filmu.

W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Controllers i wybierz polecenie Dodaj > nowy element szkieletowy.

widok powyższego kroku

W oknie dialogowym Dodawanie nowego elementu szkieletu:

  • W okienku po lewej stronie wybierz pozycję Zainstalowane>wspólne>MVC.
  • Wybierz pozycję Kontroler MVC z widokami przy użyciu platformy Entity Framework.
  • Wybierz Dodaj.

Okno dialogowe Dodawanie szkieletu

Ukończ okno dialogowe Dodawanie kontrolera MVC z widokami przy użyciu okna dialogowego Entity Framework:

  • Z listy rozwijanej Klasa modelu wybierz pozycję Movie (MvcFilm.Models).
  • W wierszu Klasy kontekstu danych wybierz + znak (plus).
    • W oknie dialogowym Dodawanie kontekstu danych jest generowana nazwa klasy MvcFilm.Data.MvcTextContext.
    • Wybierz Dodaj.
  • Z listy rozwijanej Dostawca bazy danych wybierz pozycję SQL Server.
  • Widoki i nazwa kontrolera: zachowaj wartość domyślną.
  • Wybierz Dodaj.

Dodaj kontekst danych zachowaj wartości domyślne Jeśli zostanie wyświetlony komunikat o błędzie, wybierz pozycję Dodaj po raz drugi, aby spróbować ponownie.

Tworzenie szkieletu dodaje następujące pakiety:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Tworzenie szkieletu powoduje utworzenie następujących elementów:

  • Kontroler filmów: Controllers/MoviesController.cs
  • Razor wyświetl pliki dla stron Tworzenie, Usuwanie, Szczegóły, Edytowanie i Indeks : Views/Movies/*.cshtml
  • Klasa kontekstu bazy danych: Data/MvcMovieContext.cs

Tworzenie szkieletu aktualizuje następujące elementy:

  • Wstawia wymagane odwołania do pakietu w MvcMovie.csproj pliku projektu.
  • Rejestruje kontekst bazy danych w Program.cs pliku.
  • Dodaje parametry połączenia bazy danych do appsettings.json pliku.

Automatyczne tworzenie tych plików i aktualizacji plików jest nazywane tworzeniem szkieletów.

Nie można jeszcze używać stron szkieletowych, ponieważ baza danych nie istnieje. Uruchomienie aplikacji i wybranie linku Aplikacja filmowa powoduje otwarcie bazy danych lub brak takiej tabeli: komunikat o błędzie Filmu .

Skompiluj aplikację, aby sprawdzić, czy nie ma żadnych błędów.

Migracja początkowa

EF CoreUżyj funkcji Migracje, aby utworzyć bazę danych. Migracje to zestaw narzędzi, które tworzą i aktualizują bazę danych w celu dopasowania ich do modelu danych.

Z menu Narzędzia wybierz pozycję NuGet Menedżer pakietów> Menedżer pakietów Konsola .

W konsoli Menedżer pakietów (PMC) wprowadź następujące polecenia:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: generuje Migrations/{timestamp}_InitialCreate.cs plik migracji. Argumentem InitialCreate jest nazwa migracji. Można użyć dowolnej nazwy, ale zgodnie z konwencją wybrana jest nazwa opisującą migrację. Ponieważ jest to pierwsza migracja, wygenerowana klasa zawiera kod umożliwiający utworzenie schematu bazy danych. Schemat bazy danych jest oparty na modelu określonym w MvcMovieContext klasie.

  • Update-Database: Aktualizacje bazę danych do najnowszej migracji, która została utworzona przez poprzednie polecenie. To polecenie uruchamia metodę Up w Migrations/{time-stamp}_InitialCreate.cs pliku, która tworzy bazę danych.

Polecenie Update-Database generuje następujące ostrzeżenie:

Nie określono typu dla kolumny dziesiętnej "Price" w typie jednostki "Movie". Spowoduje to dyskretne obcięcie wartości, jeśli nie mieszczą się w domyślnej precyzji i skali. Jawnie określ typ kolumny serwera SQL, który może pomieścić wszystkie wartości przy użyciu polecenia "HasColumnType()".

Zignoruj powyższe ostrzeżenie. Jest on naprawiony w późniejszym samouczku.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Coreprogramu , zobacz EF Core dokumentacja narzędzi — PMC w programie Visual Studio.

Testowanie aplikacji

Uruchom aplikację i wybierz link Aplikacja filmowa.

Jeśli wystąpi wyjątek podobny do poniższego, być może pominięto Update-Database polecenie w kroku migracji:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Uwaga

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i w formatach dat innych niż angielskie stany USA, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz ten problem z usługą GitHub.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W przypadku EF Coreprogramu dostęp do danych jest wykonywany przy użyciu modelu. Model składa się z klas jednostek i obiektu kontekstu, który reprezentuje sesję z bazą danych. Obiekt kontekstu umożliwia wykonywanie zapytań i zapisywanie danych. Kontekst bazy danych pochodzi z elementu Microsoft.EntityFrameworkCore.DbContext i określa jednostki do uwzględnienia w modelu danych.

Tworzenie szkieletu Data/MvcMovieContext.cs powoduje utworzenie klasy kontekstu bazy danych:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

Powyższy kod tworzy właściwość DbSet<Movie> reprezentującą filmy w bazie danych.

Wstrzykiwanie zależności

ASP.NET Core jest kompilowany przy użyciu wstrzykiwania zależności (DI). Usługi, takie jak kontekst bazy danych, są rejestrowane w usłudze DI w systemie Program.cs. Te usługi są udostępniane składnikom, które wymagają ich za pośrednictwem parametrów konstruktora.

Controllers/MoviesController.cs W pliku konstruktor używa wstrzykiwania zależności, aby wstrzyknąć MvcMovieContext kontekst bazy danych do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

Tworzenie szkieletu wygenerowało następujący wyróżniony kod w pliku Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));

System konfiguracji ASP.NET Core odczytuje bazę danych "MvcTextContext" parametry połączenia.

Badanie wygenerowanej bazy danych parametry połączenia

Tworzenie szkieletu dodało parametry połączenia do appsettings.json pliku:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Data Source=MvcMovieContext-ea7a4069-f366-4742-bd1c-3f753a804ce1.db"
  }
}

W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje ConnectionString klucz z appsettings.json pliku.

Klasa InitialCreate

Migrations/{timestamp}_InitialCreate.cs Sprawdź plik migracji:

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

Powyższy kod:

  • InitialCreate.Up Tworzy tabelę Movie i konfiguruje Id jako klucz podstawowy.
  • InitialCreate.Down Przywraca zmiany schematu wprowadzone przez migrację Up .

Wstrzykiwanie zależności w kontrolerze

Controllers/MoviesController.cs Otwórz plik i sprawdź konstruktor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktor używa wstrzykiwania zależności do wstrzykiwania kontekstu bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

Przetestuj stronę Tworzenie . Wprowadź i prześlij dane.

Przetestuj strony Edytuj, Szczegóły i Usuń .

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku przy użyciu słownika ViewData . Słownik ViewData jest obiektem dynamicznym, który zapewnia wygodny, opóźniony sposób przekazywania informacji do widoku.

MvC umożliwia przekazywanie silnie typiowanych obiektów modelu do widoku. To silnie typizowane podejście umożliwia sprawdzanie kodu czasu kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowanego modelu w MoviesController klasie i widokach.

Sprawdź wygenerowaną Details metodę w Controllers/MoviesController.cs pliku:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametr id jest zwykle przekazywany jako dane trasy. Na przykład https://localhost:5001/movies/details/1 zestawy:

  • Kontroler kontrolera movies , pierwszy segment adresu URL.
  • Akcja na details, drugi segment adresu URL.
  • Od id 1 do ostatniego segmentu adresu URL.

Element id można przekazać za pomocą ciągu zapytania, jak w poniższym przykładzie:

https://localhost:5001/movies/details?id=1

Parametr id jest definiowany jako typ dopuszczalny do wartości null (int?) w przypadkach, gdy wartość nie jest podana id .

Wyrażenie lambda jest przekazywane do FirstOrDefaultAsync metody , aby wybrać jednostki filmu zgodne z danymi trasy lub wartością ciągu zapytania.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Jeśli zostanie znaleziony film, wystąpienie Movie modelu zostanie przekazane do Details widoku:

return View(movie);

Sprawdź zawartość Views/Movies/Details.cshtml pliku:

@model MvcMovie.Models.Movie

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

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instrukcja @model w górnej części pliku widoku określa typ obiektu, którego oczekuje widok. Po utworzeniu kontrolera filmu dołączono następującą @model instrukcję:

@model MvcMovie.Models.Movie

Ta @model dyrektywa umożliwia dostęp do filmu przekazanego przez kontroler do widoku. Obiekt Model jest silnie typizowane. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor pomocników HTML z DisplayFor silnie typiowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok i metodę Index.cshtmlIndex w kontrolerze Filmy. Zwróć uwagę, że kod tworzy List obiekt, gdy wywołuje metodę View . Kod przekazuje tę Movies listę z Index metody akcji do widoku:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Kod zwraca szczegóły problemu, jeśli Movie właściwość kontekstu danych ma wartość null.

Po utworzeniu kontrolera filmów szkielet zawiera następującą @model instrukcję w górnej Index.cshtml części pliku:

@model IEnumerable<MvcMovie.Models.Movie>

Dyrektywa @model umożliwia dostęp do listy filmów przekazywanych przez kontroler do widoku przy użyciu silnie typizowanego Model obiektu. Na przykład w Index.cshtml widoku kod przechodzi przez filmy za pomocą foreach instrukcji na silnie typizowanego Model obiektu:

@model IEnumerable<MvcMovie.Models.Movie>

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

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </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>

Model Ponieważ obiekt jest silnie typowany jako IEnumerable<Movie> obiekt, każdy element w pętli jest wpisywany jako Movie. Między innymi kompilator weryfikuje typy używane w kodzie.

Dodatkowe zasoby

W tym samouczku klasy są dodawane do zarządzania filmami w bazie danych. Te klasy są częścią "odel" aplikacji MVC.

Te klasy modeli są używane z programem Entity Framework Core (EF Core) do pracy z bazą danych. EF Core to struktura mapowania relacyjnego (ORM, object-relational mapping), która upraszcza kod dostępu do danych, który trzeba napisać.

Utworzone klasy modeli są nazywane klasami POCO z Plain Old CLR Objects. Klasy POCO nie mają żadnej zależności od EF Coreklasy . Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku klasy modeli są tworzone najpierw i EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder >Models Dodaj>klasę. Nazwij plik Movie.cs.

Models/Movie.cs Zaktualizuj plik przy użyciu następującego kodu:

using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string? Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string? Genre { get; set; }
        public decimal Price { get; set; }
    }
}

Klasa Movie zawiera Id pole wymagane przez bazę danych dla klucza podstawowego.

Atrybut DataType on ReleaseDate określa typ danych (Date). Za pomocą tego atrybutu:

  • Użytkownik nie musi wprowadzać informacji o godzinie w polu daty.
  • Wyświetlana jest tylko data, a nie informacje o godzinie.

Adnotacje danych zostały omówione w późniejszym samouczku.

Znak zapytania po string wskazuje, że właściwość jest dopuszczana do wartości null. Aby uzyskać więcej informacji, zobacz Typy referencyjne dopuszczane do wartości null.

Dodawanie pakietów NuGet

Z menu Narzędzia wybierz pozycję NuGet Menedżer pakietów> Menedżer pakietów Konsola (PMC).

Menu PMC

W usłudze PMC uruchom następujące polecenie:

Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.SqlServer

Powyższe polecenia dodają:

  • EF Core Dostawca programu SQL Server. Pakiet dostawcy EF Core instaluje pakiet jako zależność.
  • Narzędzia używane przez pakiety zainstalowane automatycznie w kroku tworzenia szkieletu w dalszej części tego samouczka.

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

Strony filmów szkieletowych

Narzędzie do tworzenia szkieletów umożliwia tworzenie Createstron , Read, Updatei Delete (CRUD) dla modelu filmu.

W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Controllers i wybierz polecenie Dodaj > nowy element szkieletowy.

widok powyższego kroku

W oknie dialogowym Dodawanie szkieletu wybierz pozycję Kontroler MVC z widokami, używając polecenia Entity Framework > Add.

Okno dialogowe Dodawanie szkieletu

Ukończ okno dialogowe Dodawanie kontrolera MVC z widokami przy użyciu okna dialogowego Entity Framework:

  • Z listy rozwijanej Klasa modelu wybierz pozycję Movie (MvcFilm.Models).
  • W wierszu Klasy kontekstu danych wybierz + znak (plus).
    • W oknie dialogowym Dodawanie kontekstu danych jest generowana nazwa klasy MvcFilm.Data.MvcTextContext.
    • Wybierz Dodaj.
  • Widoki i nazwa kontrolera: zachowaj wartość domyślną.
  • Wybierz Dodaj.

Dodaj kontekst danych zachowaj wartości domyślne

Jeśli zostanie wyświetlony komunikat o błędzie, wybierz pozycję Dodaj po raz drugi, aby spróbować ponownie.

Tworzenie szkieletu aktualizuje następujące elementy:

  • Wstawia wymagane odwołania do pakietu w MvcMovie.csproj pliku projektu.
  • Rejestruje kontekst bazy danych w Program.cs pliku.
  • Dodaje parametry połączenia bazy danych do appsettings.json pliku.

Tworzenie szkieletu powoduje utworzenie następujących elementów:

  • Kontroler filmów: Controllers/MoviesController.cs
  • Razor wyświetl pliki dla stron Tworzenie, Usuwanie, Szczegóły, Edytowanie i Indeks : Views/Movies/*.cshtml
  • Klasa kontekstu bazy danych: Data/MvcMovieContext.cs

Automatyczne tworzenie tych plików i aktualizacji plików jest nazywane tworzeniem szkieletów.

Nie można jeszcze używać stron szkieletowych, ponieważ baza danych nie istnieje. Uruchomienie aplikacji i wybranie linku Aplikacja filmowa powoduje otwarcie bazy danych lub brak takiej tabeli: komunikat o błędzie Filmu .

Tworzenie aplikacji

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 i typy referencyjne dopuszczane do wartości null.

Aby wyeliminować ostrzeżenia z typów odwołań dopuszczanych do wartości null, usuń następujący wiersz z MvcMovie.csproj pliku:

<Nullable>enable</Nullable>

Mamy nadzieję rozwiązać ten problem w następnej wersji.

Migracja początkowa

EF CoreUżyj funkcji Migracje, aby utworzyć bazę danych. Migracje to zestaw narzędzi, które tworzą i aktualizują bazę danych w celu dopasowania ich do modelu danych.

Z menu Narzędzia wybierz pozycję NuGet Menedżer pakietów> Menedżer pakietów Konsola .

W konsoli Menedżer pakietów (PMC) wprowadź następujące polecenia:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: generuje Migrations/{timestamp}_InitialCreate.cs plik migracji. Argumentem InitialCreate jest nazwa migracji. Można użyć dowolnej nazwy, ale zgodnie z konwencją wybrana jest nazwa opisującą migrację. Ponieważ jest to pierwsza migracja, wygenerowana klasa zawiera kod umożliwiający utworzenie schematu bazy danych. Schemat bazy danych jest oparty na modelu określonym w MvcMovieContext klasie.

  • Update-Database: Aktualizacje bazę danych do najnowszej migracji, która została utworzona przez poprzednie polecenie. To polecenie uruchamia metodę Up w Migrations/{time-stamp}_InitialCreate.cs pliku, która tworzy bazę danych.

Polecenie Update-Database generuje następujące ostrzeżenie:

Nie określono typu dla kolumny dziesiętnej "Price" w typie jednostki "Movie". Spowoduje to dyskretne obcięcie wartości, jeśli nie mieszczą się w domyślnej precyzji i skali. Jawnie określ typ kolumny serwera SQL, który może pomieścić wszystkie wartości przy użyciu polecenia "HasColumnType()".

Zignoruj powyższe ostrzeżenie. Jest on naprawiony w późniejszym samouczku.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Coreprogramu , zobacz EF Core dokumentacja narzędzi — PMC w programie Visual Studio.

Testowanie aplikacji

Uruchom aplikację i wybierz link Aplikacja filmowa.

Jeśli wystąpi wyjątek podobny do poniższego, być może pominięto krok migracji:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Uwaga

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i w formatach dat innych niż angielskie stany USA, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz ten problem z usługą GitHub.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W przypadku EF Coreprogramu dostęp do danych jest wykonywany przy użyciu modelu. Model składa się z klas jednostek i obiektu kontekstu, który reprezentuje sesję z bazą danych. Obiekt kontekstu umożliwia wykonywanie zapytań i zapisywanie danych. Kontekst bazy danych pochodzi z elementu Microsoft.EntityFrameworkCore.DbContext i określa jednostki do uwzględnienia w modelu danych.

Tworzenie szkieletu Data/MvcMovieContext.cs powoduje utworzenie klasy kontekstu bazy danych:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<MvcMovie.Models.Movie> Movie { get; set; }
    }
}

Powyższy kod tworzy właściwość DbSet<Movie> reprezentującą filmy w bazie danych.

Wstrzykiwanie zależności

ASP.NET Core jest kompilowany przy użyciu wstrzykiwania zależności (DI). Usługi, takie jak kontekst bazy danych, są rejestrowane w usłudze DI w systemie Program.cs. Te usługi są udostępniane składnikom, które wymagają ich za pośrednictwem parametrów konstruktora.

Controllers/MoviesController.cs W pliku konstruktor używa wstrzykiwania zależności, aby wstrzyknąć MvcMovieContext kontekst bazy danych do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

Tworzenie szkieletu wygenerowało następujący wyróżniony kod w pliku Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));

System konfiguracji ASP.NET Core odczytuje bazę danych "MvcTextContext" parametry połączenia.

Badanie wygenerowanej bazy danych parametry połączenia

Tworzenie szkieletu dodało parametry połączenia do appsettings.json pliku:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-7dc5;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje ConnectionString klucz z appsettings.json pliku.

Klasa InitialCreate

Migrations/{timestamp}_InitialCreate.cs Sprawdź plik migracji:

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    public partial class InitialCreate : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Movie",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                    Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Movie", x => x.Id);
                });
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Movie");
        }
    }
}

Powyższy kod:

  • InitialCreate.Up Tworzy tabelę Movie i konfiguruje Id jako klucz podstawowy.
  • InitialCreate.Down Przywraca zmiany schematu wprowadzone przez migrację Up .

Wstrzykiwanie zależności w kontrolerze

Controllers/MoviesController.cs Otwórz plik i sprawdź konstruktor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktor używa wstrzykiwania zależności do wstrzykiwania kontekstu bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

Przetestuj stronę Tworzenie . Wprowadź i prześlij dane.

Przetestuj strony Edytuj, Szczegóły i Usuń .

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku przy użyciu słownika ViewData . Słownik ViewData jest obiektem dynamicznym, który zapewnia wygodny, opóźniony sposób przekazywania informacji do widoku.

MvC umożliwia przekazywanie silnie typiowanych obiektów modelu do widoku. To silnie typizowane podejście umożliwia sprawdzanie kodu czasu kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowanego modelu w MoviesController klasie i widokach.

Sprawdź wygenerowaną Details metodę w Controllers/MoviesController.cs pliku:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametr id jest zwykle przekazywany jako dane trasy. Na przykład https://localhost:5001/movies/details/1 zestawy:

  • Kontroler kontrolera movies , pierwszy segment adresu URL.
  • Akcja na details, drugi segment adresu URL.
  • Od id 1 do ostatniego segmentu adresu URL.

Element id można przekazać za pomocą ciągu zapytania, jak w poniższym przykładzie:

https://localhost:5001/movies/details?id=1

Parametr id jest definiowany jako typ dopuszczalny do wartości null (int?) w przypadkach, gdy wartość nie jest podana id .

Wyrażenie lambda jest przekazywane do FirstOrDefaultAsync metody , aby wybrać jednostki filmu zgodne z danymi trasy lub wartością ciągu zapytania.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Jeśli zostanie znaleziony film, wystąpienie Movie modelu zostanie przekazane do Details widoku:

return View(movie);

Sprawdź zawartość Views/Movies/Details.cshtml pliku:

@model MvcMovie.Models.Movie

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

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class = "col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class = "col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instrukcja @model w górnej części pliku widoku określa typ obiektu, którego oczekuje widok. Po utworzeniu kontrolera filmu dołączono następującą @model instrukcję:

@model MvcMovie.Models.Movie

Ta @model dyrektywa umożliwia dostęp do filmu przekazanego przez kontroler do widoku. Obiekt Model jest silnie typizowane. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor pomocników HTML z DisplayFor silnie typiowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok i metodę Index.cshtmlIndex w kontrolerze Filmy. Zwróć uwagę, że kod tworzy List obiekt, gdy wywołuje metodę View . Kod przekazuje tę Movies listę z Index metody akcji do widoku:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Po utworzeniu kontrolera filmów szkielet zawiera następującą @model instrukcję w górnej Index.cshtml części pliku:

@model IEnumerable<MvcMovie.Models.Movie>

Dyrektywa @model umożliwia dostęp do listy filmów przekazywanych przez kontroler do widoku przy użyciu silnie typizowanego Model obiektu. Na przykład w Index.cshtml widoku kod przechodzi przez filmy za pomocą foreach instrukcji na silnie typizowanego Model obiektu:

@model IEnumerable<MvcMovie.Models.Movie>

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

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </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>

Model Ponieważ obiekt jest silnie typowany jako IEnumerable<Movie> obiekt, każdy element w pętli jest wpisywany jako Movie. Między innymi kompilator weryfikuje typy używane w kodzie.

Dodatkowe zasoby

W tym samouczku klasy są dodawane do zarządzania filmami w bazie danych. Te klasy są częścią "odel" aplikacji MVC.

Te klasy modeli są używane z programem Entity Framework Core (EF Core) do pracy z bazą danych. EF Core to struktura mapowania relacyjnego (ORM, object-relational mapping), która upraszcza kod dostępu do danych, który trzeba napisać.

Utworzone klasy modeli są nazywane klasami POCO z Plain Old CLR Objects. Klasy POCO nie mają żadnej zależności od EF Coreklasy . Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku klasy modeli są tworzone najpierw i EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder >Models Dodaj>klasę. Nazwij plik Movie.cs.

Models/Movie.cs Zaktualizuj plik przy użyciu następującego kodu:

using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

Klasa Movie zawiera Id pole wymagane przez bazę danych dla klucza podstawowego.

Atrybut DataType on ReleaseDate określa typ danych (Date). Za pomocą tego atrybutu:

  • Użytkownik nie musi wprowadzać informacji o godzinie w polu daty.
  • Wyświetlana jest tylko data, a nie informacje o godzinie.

Adnotacje danych zostały omówione w późniejszym samouczku.

Dodawanie pakietów NuGet

Z menu Narzędzia wybierz pozycję NuGet Menedżer pakietów> Menedżer pakietów Konsola (PMC).

Menu PMC

W usłudze PMC uruchom następujące polecenie:

Install-Package Microsoft.EntityFrameworkCore.Design

Powyższe polecenia dodają:

  • EF Core Dostawca programu SQL Server. Pakiet dostawcy EF Core instaluje pakiet jako zależność.
  • Narzędzia używane przez pakiety zainstalowane automatycznie w kroku tworzenia szkieletu w dalszej części tego samouczka.

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

Strony filmów szkieletowych

Narzędzie do tworzenia szkieletów umożliwia tworzenie Createstron , Read, Updatei Delete (CRUD) dla modelu filmu.

W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Controllers i wybierz polecenie Dodaj > nowy element szkieletowy.

widok powyższego kroku

W oknie dialogowym Dodawanie szkieletu wybierz pozycję Kontroler MVC z widokami, używając polecenia Entity Framework > Add.

Okno dialogowe Dodawanie szkieletu

Ukończ okno dialogowe Dodawanie kontrolera MVC z widokami przy użyciu okna dialogowego Entity Framework:

  • Z listy rozwijanej Klasa modelu wybierz pozycję Movie (MvcFilm.Models).
  • W wierszu Klasy kontekstu danych wybierz + znak (plus).
    • W oknie dialogowym Dodawanie kontekstu danych jest generowana nazwa klasy MvcFilm.Data.MvcTextContext.
    • Wybierz Dodaj.
  • Widoki i nazwa kontrolera: zachowaj wartość domyślną.
  • Wybierz Dodaj.

Dodaj kontekst danych zachowaj wartości domyślne

Tworzenie szkieletu aktualizuje następujące elementy:

  • Wstawia wymagane odwołania do pakietu w MvcMovie.csproj pliku projektu.
  • Rejestruje kontekst bazy danych w Startup.ConfigureServicesStartup.cs pliku.
  • Dodaje parametry połączenia bazy danych do appsettings.json pliku.

Tworzenie szkieletu powoduje utworzenie następujących elementów:

  • Kontroler filmów: Controllers/MoviesController.cs
  • Razor wyświetl pliki dla stron Tworzenie, Usuwanie, Szczegóły, Edytowanie i Indeks : Views/Movies/*.cshtml
  • Klasa kontekstu bazy danych: Data/MvcMovieContext.cs

Automatyczne tworzenie tych plików i aktualizacji plików jest nazywane tworzeniem szkieletów.

Nie można jeszcze używać stron szkieletowych, ponieważ baza danych nie istnieje. Uruchomienie aplikacji i wybranie linku Aplikacja filmowa powoduje otwarcie bazy danych lub brak takiej tabeli: komunikat o błędzie Filmu .

Migracja początkowa

EF CoreUżyj funkcji Migracje, aby utworzyć bazę danych. Migracje to zestaw narzędzi, które tworzą i aktualizują bazę danych w celu dopasowania ich do modelu danych.

Z menu Narzędzia wybierz pozycję NuGet Menedżer pakietów> Menedżer pakietów Konsola .

W konsoli Menedżer pakietów (PMC) wprowadź następujące polecenia:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: generuje Migrations/{timestamp}_InitialCreate.cs plik migracji. Argumentem InitialCreate jest nazwa migracji. Można użyć dowolnej nazwy, ale zgodnie z konwencją wybrana jest nazwa opisującą migrację. Ponieważ jest to pierwsza migracja, wygenerowana klasa zawiera kod umożliwiający utworzenie schematu bazy danych. Schemat bazy danych jest oparty na modelu określonym w MvcMovieContext klasie.

  • Update-Database: Aktualizacje bazę danych do najnowszej migracji, która została utworzona przez poprzednie polecenie. To polecenie uruchamia metodę Up w Migrations/{time-stamp}_InitialCreate.cs pliku, która tworzy bazę danych.

Polecenie Update-Database generuje następujące ostrzeżenie:

Nie określono typu dla kolumny dziesiętnej "Price" w typie jednostki "Movie". Spowoduje to dyskretne obcięcie wartości, jeśli nie mieszczą się w domyślnej precyzji i skali. Jawnie określ typ kolumny serwera SQL, który może pomieścić wszystkie wartości przy użyciu polecenia "HasColumnType()".

Zignoruj powyższe ostrzeżenie. Jest on naprawiony w późniejszym samouczku.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Coreprogramu , zobacz EF Core dokumentacja narzędzi — PMC w programie Visual Studio.

Testowanie aplikacji

Uruchom aplikację i wybierz link Aplikacja filmowa.

Jeśli wystąpi wyjątek podobny do poniższego, być może pominięto krok migracji:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Uwaga

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i w formatach dat innych niż angielskie stany USA, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz ten problem z usługą GitHub.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W przypadku EF Coreprogramu dostęp do danych jest wykonywany przy użyciu modelu. Model składa się z klas jednostek i obiektu kontekstu, który reprezentuje sesję z bazą danych. Obiekt kontekstu umożliwia wykonywanie zapytań i zapisywanie danych. Kontekst bazy danych pochodzi z elementu Microsoft.EntityFrameworkCore.DbContext i określa jednostki do uwzględnienia w modelu danych.

Tworzenie szkieletu Data/MvcMovieContext.cs powoduje utworzenie klasy kontekstu bazy danych:

using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<Movie> Movie { get; set; }
    }
}

Powyższy kod tworzy właściwość DbSet<Movie> reprezentującą filmy w bazie danych.

ASP.NET Core jest kompilowany przy użyciu wstrzykiwania zależności (DI). Usługi, takie jak kontekst bazy danych, muszą być zarejestrowane w usłudze DI w systemie Startup. Składniki, które wymagają tych usług, są dostarczane za pomocą parametrów konstruktora.

Controllers/MoviesController.cs W pliku konstruktor używa wstrzykiwania zależności, aby wstrzyknąć MvcMovieContext kontekst bazy danych do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

Tworzenie szkieletu wygenerowało następujący wyróżniony kod w pliku Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("MvcMovieContext")));
}

System konfiguracji ASP.NET Core odczytuje bazę danych "MvcTextContext" parametry połączenia.

Badanie wygenerowanej bazy danych parametry połączenia

Tworzenie szkieletu dodało parametry połączenia do appsettings.json pliku:

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

W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje ConnectionString klucz z appsettings.json pliku.

Klasa InitialCreate

Migrations/{timestamp}_InitialCreate.cs Sprawdź plik migracji:

public partial class InitialCreate : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Movie",
            columns: table => new
            {
                Id = table.Column<int>(type: "int", nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1"),
                Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                ReleaseDate = table.Column<DateTime>(type: "datetime2", nullable: false),
                Genre = table.Column<string>(type: "nvarchar(max)", nullable: true),
                Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Movie", x => x.Id);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Movie");
    }
}

Powyższy kod:

  • InitialCreate.Up Tworzy tabelę Movie i konfiguruje Id jako klucz podstawowy.
  • InitialCreate.Down Przywraca zmiany schematu wprowadzone przez migrację Up .

Wstrzykiwanie zależności w kontrolerze

Controllers/MoviesController.cs Otwórz plik i sprawdź konstruktor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktor używa wstrzykiwania zależności do wstrzykiwania kontekstu bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

Przetestuj stronę Tworzenie . Wprowadź i prześlij dane.

Przetestuj strony Edytuj, Szczegóły i Usuń .

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku przy użyciu słownika ViewData . Słownik ViewData jest obiektem dynamicznym, który zapewnia wygodny, opóźniony sposób przekazywania informacji do widoku.

MvC umożliwia przekazywanie silnie typiowanych obiektów modelu do widoku. To silnie typizowane podejście umożliwia sprawdzanie kodu czasu kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowanego modelu w MoviesController klasie i widokach.

Sprawdź wygenerowaną Details metodę w Controllers/MoviesController.cs pliku:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametr id jest zwykle przekazywany jako dane trasy. Na przykład https://localhost:5001/movies/details/1 zestawy:

  • Kontroler kontrolera movies , pierwszy segment adresu URL.
  • Akcja na details, drugi segment adresu URL.
  • Od id 1 do ostatniego segmentu adresu URL.

Element id można przekazać za pomocą ciągu zapytania, jak w poniższym przykładzie:

https://localhost:5001/movies/details?id=1

Parametr id jest definiowany jako typ dopuszczalny do wartości null (int?) w przypadkach, gdy wartość nie jest podana id .

Wyrażenie lambda jest przekazywane do FirstOrDefaultAsync metody , aby wybrać jednostki filmu zgodne z danymi trasy lub wartością ciągu zapytania.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Jeśli zostanie znaleziony film, wystąpienie Movie modelu zostanie przekazane do Details widoku:

return View(movie);

Sprawdź zawartość Views/Movies/Details.cshtml pliku:

@model MvcMovie.Models.Movie

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

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instrukcja @model w górnej części pliku widoku określa typ obiektu, którego oczekuje widok. Po utworzeniu kontrolera filmu dołączono następującą @model instrukcję:

@model MvcMovie.Models.Movie

Ta @model dyrektywa umożliwia dostęp do filmu przekazanego przez kontroler do widoku. Obiekt Model jest silnie typizowane. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor pomocników HTML z DisplayFor silnie typiowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok i metodę Index.cshtmlIndex w kontrolerze Filmy. Zwróć uwagę, że kod tworzy List obiekt, gdy wywołuje metodę View . Kod przekazuje tę Movies listę z Index metody akcji do widoku:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Po utworzeniu kontrolera filmów szkielet zawiera następującą @model instrukcję w górnej Index.cshtml części pliku:

@model IEnumerable<MvcMovie.Models.Movie>

Dyrektywa @model umożliwia dostęp do listy filmów przekazywanych przez kontroler do widoku przy użyciu silnie typizowanego Model obiektu. Na przykład w Index.cshtml widoku kod przechodzi przez filmy za pomocą foreach instrukcji na silnie typizowanego Model obiektu:

@model IEnumerable<MvcMovie.Models.Movie>

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

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </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>

Model Ponieważ obiekt jest silnie typowany jako IEnumerable<Movie> obiekt, każdy element w pętli jest wpisywany jako Movie. Między innymi kompilator weryfikuje typy używane w kodzie.

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.

Dodatkowe zasoby

W tym samouczku klasy są dodawane do zarządzania filmami w bazie danych. Te klasy są częścią "odel" aplikacji MVC.

Te klasy modeli są używane z programem Entity Framework Core (EF Core) do pracy z bazą danych. EF Core to struktura mapowania relacyjnego (ORM, object-relational mapping), która upraszcza kod dostępu do danych, który trzeba napisać.

Utworzone klasy modeli są nazywane klasami POCO z Plain Old CLR Objects. Klasy POCO nie mają żadnej zależności od EF Coreklasy . Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku klasy modeli są tworzone najpierw i EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder >Models Dodaj>klasę. Nazwij plik Movie.cs.

Movie.cs Zaktualizuj plik przy użyciu następującego kodu:

using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

Klasa Movie zawiera Id pole wymagane przez bazę danych dla klucza podstawowego.

Atrybut DataType on ReleaseDate określa typ danych (Date). Za pomocą tego atrybutu:

  • Użytkownik nie musi wprowadzać informacji o godzinie w polu daty.
  • Wyświetlana jest tylko data, a nie informacje o godzinie.

Adnotacje danych zostały omówione w późniejszym samouczku.

Dodawanie pakietów NuGet

Z menu Narzędzia wybierz pozycję NuGet Menedżer pakietów> Menedżer pakietów Konsola (PMC).

Menu PMC

W usłudze PMC uruchom następujące polecenie:

Install-Package Microsoft.EntityFrameworkCore.SqlServer

Poprzednie polecenie dodaje dostawcę EF Core programu SQL Server. Pakiet dostawcy EF Core instaluje pakiet jako zależność. Dodatkowe pakiety są instalowane automatycznie w kroku tworzenia szkieletu w dalszej części samouczka.

Tworzenie klasy kontekstu bazy danych

Klasa kontekstu bazy danych jest wymagana do koordynowania EF Core funkcjonalności (Tworzenie, odczyt, aktualizacja, usuwanie) dla Movie modelu. Kontekst bazy danych pochodzi z Microsoft.EntityFrameworkCore.DbContext i określa jednostki do uwzględnienia w modelu danych.

Utwórz folder Dane.

Data/MvcMovieContext.cs Dodaj plik z następującym kodem:

using Microsoft.EntityFrameworkCore;
using MvcMovie.Models;

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

        public DbSet<Movie> Movie { get; set; }
    }
}

Powyższy kod tworzy właściwość DbSet<Movie> dla zestawu jednostek. W terminologii platformy Entity Framework zestaw jednostek zwykle odpowiada tabeli bazy danych. Jednostka odpowiada wierszowi w tabeli.

Rejestrowanie kontekstu bazy danych

ASP.NET Core jest kompilowany przy użyciu wstrzykiwania zależności (DI). Usługi (takie jak kontekst bazy danych) muszą być zarejestrowane z di podczas uruchamiania EF Core 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. W tej sekcji zarejestrujesz kontekst bazy danych w kontenerze DI.

Dodaj następujące using instrukcje w górnej części elementu Startup.cs:

using MvcMovie.Data;
using Microsoft.EntityFrameworkCore;

Dodaj następujący wyróżniony kod w Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("MvcMovieContext")));
}

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.

Badanie parametry połączenia bazy danych

Dodaj parametry połączenia do appsettings.json pliku:

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

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

Strony filmów szkieletowych

Użyj narzędzia do tworzenia szkieletów, aby tworzyć strony tworzenia, odczytu, aktualizacji i usuwania (CRUD) dla modelu filmu.

W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder > Kontrolery Dodaj > nowy element szkieletowy.

widok powyższego kroku

W oknie dialogowym Dodawanie szkieletu wybierz pozycję Kontroler MVC z widokami, używając polecenia Entity Framework > Add.

Okno dialogowe Dodawanie szkieletu

Ukończ okno dialogowe Dodawanie kontrolera:

  • Model class:Movie (MvcFilm.Models)
  • Klasa kontekstu danych:MvcFilmContext (MvcFilm.Data)

Dodawanie kontekstu danych

  • Widoki: pozostaw zaznaczoną wartość domyślną każdej opcji
  • Nazwa kontrolera: Zachowaj domyślny kontroler MoviesController
  • Wybierz Dodaj

Program Visual Studio tworzy:

  • Kontroler filmów (Controllers/MoviesController.cs)
  • Razor wyświetlanie plików dla stron tworzenia, usuwania, szczegółów, edycji i indeksu (*Views/Movies/'.cshtml')

Automatyczne tworzenie tych plików jest nazywane tworzeniem szkieletów.

Nie można jeszcze używać stron szkieletowych, ponieważ baza danych nie istnieje. Jeśli uruchomisz aplikację i klikniesz link Aplikacja filmowa, otrzymasz komunikat o błędzie Nie można otworzyć bazy danych lub nie ma takiej tabeli: Film .

Migracja początkowa

EF CoreUżyj funkcji Migracje, aby utworzyć bazę danych. Migracje to zestaw narzędzi, które umożliwiają tworzenie i aktualizowanie bazy danych w celu dopasowania ich do modelu danych.

Z menu Narzędzia wybierz pozycję NuGet Menedżer pakietów> Menedżer pakietów Konsola (PMC).

W usłudze PMC wprowadź następujące polecenia:

Add-Migration InitialCreate
Update-Database
  • Add-Migration InitialCreate: generuje Migrations/{timestamp}_InitialCreate.cs plik migracji. Argumentem InitialCreate jest nazwa migracji. Można użyć dowolnej nazwy, ale zgodnie z konwencją wybrana jest nazwa opisującą migrację. Ponieważ jest to pierwsza migracja, wygenerowana klasa zawiera kod umożliwiający utworzenie schematu bazy danych. Schemat bazy danych jest oparty na modelu określonym w MvcMovieContext klasie.

  • Update-Database: Aktualizacje bazę danych do najnowszej migracji, która została utworzona przez poprzednie polecenie. To polecenie uruchamia metodę Up w Migrations/{time-stamp}_InitialCreate.cs pliku, która tworzy bazę danych.

    Polecenie aktualizacji bazy danych generuje następujące ostrzeżenie:

    Nie określono typu dla kolumny dziesiętnej "Price" w typie jednostki "Movie". Spowoduje to dyskretne obcięcie wartości, jeśli nie mieszczą się w domyślnej precyzji i skali. Jawnie określ typ kolumny serwera SQL, który może pomieścić wszystkie wartości przy użyciu polecenia "HasColumnType()".

    To ostrzeżenie można zignorować. Zostanie ono naprawione w późniejszym samouczku.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Coreprogramu , zobacz EF Core dokumentacja narzędzi — PMC w programie Visual Studio.

InitialCreate, klasa

Migrations/{timestamp}_InitialCreate.cs Sprawdź plik migracji:

public partial class InitialCreate : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Movie",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:ValueGenerationStrategy", 
                                 SqlServerValueGenerationStrategy.IdentityColumn),
                Title = table.Column<string>(nullable: true),
                ReleaseDate = table.Column<DateTime>(nullable: false),
                Genre = table.Column<string>(nullable: true),
                Price = table.Column<decimal>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_Movie", x => x.Id);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "Movie");
    }
}

Metoda Up tworzy tabelę Movie i konfiguruje Id jako klucz podstawowy. Metoda Down przywraca zmiany schematu wprowadzone przez migrację Up .

Testowanie aplikacji

  • Uruchom aplikację i kliknij link Aplikacja filmowa.

    Jeśli wystąpi wyjątek podobny do jednego z następujących:

SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.

Prawdopodobnie pominięto krok migracji.

  • Przetestuj stronę Tworzenie . Wprowadź i prześlij dane.

    Uwaga

    W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż angielski, które używają przecinka (",") dla punktu dziesiętnego i w formatach dat innych niż angielskie stany USA, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz ten problem z usługą GitHub.

  • Przetestuj strony Edytuj, Szczegóły i Usuń .

Wstrzykiwanie zależności w kontrolerze

Controllers/MoviesController.cs Otwórz plik i sprawdź konstruktor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

    public MoviesController(MvcMovieContext context)
    {
        _context = context;
    }

Konstruktor używa wstrzykiwania zależności do wstrzykiwania kontekstu bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

Silnie typizowane modele i @model słowo kluczowe

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku przy użyciu słownika ViewData . Słownik ViewData jest obiektem dynamicznym, który zapewnia wygodny, opóźniony sposób przekazywania informacji do widoku.

MvC zapewnia również możliwość przekazywania silnie typiowanych obiektów modelu do widoku. To silnie typizowane podejście umożliwia sprawdzanie kodu czasu kompilacji. Mechanizm tworzenia szkieletów używał tego podejścia (czyli przekazywania silnie typizowanego MoviesController modelu) z klasą i widokami.

Sprawdź wygenerowaną Details metodę w Controllers/MoviesController.cs pliku:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.Id == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

Parametr id jest zwykle przekazywany jako dane trasy. Na przykład https://localhost:5001/movies/details/1 zestawy:

  • Kontroler do movies kontrolera (pierwszy segment adresu URL).
  • Akcja na details (drugi segment adresu URL).
  • Identyfikator na 1 (ostatni segment adresu URL).

Możesz również przekazać element id za pomocą ciągu zapytania w następujący sposób:

https://localhost:5001/movies/details?id=1

Parametr id jest definiowany jako typ dopuszczalny wartości null (int?) w przypadku, gdy wartość identyfikatora nie jest podana.

Wyrażenie lambda jest przekazywane do, aby FirstOrDefaultAsync wybrać jednostki filmu, które pasują do danych trasy lub wartości ciągu zapytania.

var movie = await _context.Movie
    .FirstOrDefaultAsync(m => m.Id == id);

Jeśli zostanie znaleziony film, wystąpienie Movie modelu zostanie przekazane do Details widoku:

return View(movie);

Sprawdź zawartość Views/Movies/Details.cshtml pliku:

@model MvcMovie.Models.Movie

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

<h1>Details</h1>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Price)
        </dd>
    </dl>
</div>
<div>
    <a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
    <a asp-action="Index">Back to List</a>
</div>

Instrukcja @model w górnej części pliku widoku określa typ obiektu, którego oczekuje widok. Po utworzeniu kontrolera filmu dołączono następującą @model instrukcję:

@model MvcMovie.Models.Movie

Ta @model dyrektywa umożliwia dostęp do filmu przekazanego przez kontroler do widoku. Obiekt Model jest silnie typizowane. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor pomocników HTML z DisplayFor silnie typiowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok i metodę Index.cshtmlIndex w kontrolerze Filmy. Zwróć uwagę, że kod tworzy List obiekt, gdy wywołuje metodę View . Kod przekazuje tę Movies listę z Index metody akcji do widoku:

// GET: Movies
public async Task<IActionResult> Index()
{
    return View(await _context.Movie.ToListAsync());
}

Po utworzeniu kontrolera filmów szkielet zawiera następującą @model instrukcję w górnej Index.cshtml części pliku:

@model IEnumerable<MvcMovie.Models.Movie>

Dyrektywa @model umożliwia dostęp do listy filmów przekazywanych przez kontroler do widoku przy użyciu obiektu silnie typizowanego Model . Na przykład w Index.cshtml widoku kod przechodzi przez filmy za pomocą foreach instrukcji na silnie typizowanego Model obiektu:

@model IEnumerable<MvcMovie.Models.Movie>

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

<h1>Index</h1>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </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>

Model Ponieważ obiekt jest silnie typowany (jako IEnumerable<Movie> obiekt), każdy element w pętli jest typowany jako Movie. Między innymi oznacza to, że uzyskujesz sprawdzanie czasu kompilacji kodu.

Dodatkowe zasoby