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

Note

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz artykuł w wersji .NET 10.

Warning

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz .NET i .NET Core Support Policy. Aby zapoznać się z bieżącą wersją, zobacz artykuł w wersji .NET 10.

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

Te klasy modeli są używane z 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 są zależne od EF Core. Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku najpierw tworzone są klasy modeli, a następnie EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder Models, dodaj>>. 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ść może mieć wartość null. Aby uzyskać więcej informacji, zobacz Typy referencyjne dopuszczane do wartości null.

Dodawanie pakietów NuGet

Visual Studio automatycznie instaluje wymagane pakiety.

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

Strony filmów szablonowych

Narzędzie do generowania szablonów umożliwia wygenerowanie stron Create, Read, Update i Delete (CRUD) dla modelu filmu.

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

Widok elementu menu, aby dodać nowy element szkieletowy.

W oknie dialogowym Dodaj nowy szablonowany element:

  • W okienku po lewej stronie wybierz pozycję Zainstalowane>Common>MVC.
  • Wybierz kontroler MVC z widokami przy użyciu Entity Framework.
  • Wybierz Dodaj.

Okno dialogowe Dodaj szkielet.

Uzupełnij okno dialogowe Dodaj kontroler MVC z widokami, używając Entity Framework:

  • Z listy rozwijanej Klasa modelu wybierz pozycję Movie (MvcMovie.Models).
  • W wierszu Klasy kontekstu danych wybierz znak + (plus).
    • W oknie dialogowym Dodaj Kontekst Danych generowana jest nazwa klasy MvcMovie.Data.MvcMovieContext.
    • Wybierz Dodaj.
  • Na liście rozwijanej Dostawca bazy danych wybierz 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.

Skafold dodaje następujące pakiety:

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

Tworzenie szkieletu powoduje następujące elementy:

  • 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

Szkieletowanie aktualizuje następujące:

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

Automatyczne tworzenie tych plików i aktualizacji plików jest nazywane szkieletowaniem.

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

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

Migracja początkowa

EF Core Uż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 Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console .

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

Add-Migration InitialCreate

  • 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.

Zostanie wyświetlone następujące ostrzeżenie, które zostało rozwiązane w późniejszym kroku:

Nie określono typu przechowywania 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".

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

Update-Database

  • Update-Database: aktualizuje 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.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Core, zobacz EF Core - dokumentację narzędzi PMC w Visual Studio.

Testowanie aplikacji

Uruchom aplikację i wybierz link Aplikacja filmowa.

Aplikacja pokazująca widok aplikacji filmowej.

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.

Note

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż anglojęzyczne, które stosują przecinek (",") jako separator dziesiętny oraz dla formatów dat innych niż amerykańskie, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz this GitHub problem.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W EF Core dostęp do danych odbywa się 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 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; } = default!;
    }
}

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

Wstrzykiwanie zależności

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

W pliku konstruktor używa wstrzykiwania zależności , aby wstrzyknąć 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") ?? throw new InvalidOperationException("Connection string 'MvcMovieContext' not found.")));

System konfiguracji ASP.NET Core odczytuje ciąg połączenia bazy danych "MvcMovieContext".

Sprawdzenie wygenerowanego ciągu połączenia z bazą danych

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

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-4ebefa10-de29-4dea-b2ad-8a8dc6bcf374;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

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

Klasa InitialCreate

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

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    /// <inheritdoc />
    public partial class InitialCreate : Migration
    {
        /// <inheritdoc />
        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);
                });
        }

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

W przedstawionym wyżej kodzie:

  • 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

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

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Konstruktor używa Dependency Injection, aby wstrzyknąć kontekst bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

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

Przetestuj stronę Edytuj, stronę Szczegóły i stronę Usuwanie.

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku, używając 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 typizowanych obiektów modelu do widoku. Silnie typizowane podejście umożliwia sprawdzanie kodu w czasie kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowany model w klasie MoviesController 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:{PORT}/movies/details/1 ustawia:

  • Kontroler do kontrolera movies, pierwszy segment adresu URL.
  • Działanie dla details, drugiego segmentu adresu URL.
  • id do 1, ostatni segment adresu URL.

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

https://localhost:{PORT}/movies/details?id=1

Parametr id jest definiowany jako typ dopuszczający wartość null (int?) w przypadkach, gdy wartość id nie jest podana.

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, który kontroler przekazał widokowi. Obiekt Model jest silnie typizowany. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor Helperów HTML z DisplayFor silnie typowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok Index.cshtml i metodę Index 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 widoku Index.cshtml kod przechodzi przez filmy za pomocą instrukcji foreach dla silnie typizowanego obiektu Model.

@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>

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

Dodatkowe zasoby

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

Te klasy modeli są używane z 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 są zależne od EF Core. Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku najpierw tworzone są klasy modeli, a następnie EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder Models, dodaj>>. 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ść może mieć wartość null. Aby uzyskać więcej informacji, zobacz Typy referencyjne dopuszczane do wartości null.

Dodawanie pakietów NuGet

Visual Studio automatycznie instaluje wymagane pakiety.

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

Strony filmów szablonowych

Narzędzie do generowania szablonów umożliwia wygenerowanie stron Create, Read, Update i Delete (CRUD) dla modelu filmu.

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

widok powyższego kroku

W oknie dialogowym Dodaj nowy szablonowany element:

  • W okienku po lewej stronie wybierz pozycję Zainstalowane>Common>MVC.
  • Wybierz kontroler MVC z widokami przy użyciu Entity Framework.
  • Wybierz Dodaj.

Dodaj Szkielet - okno dialogowe

Uzupełnij okno dialogowe Dodaj kontroler MVC z widokami, używając Entity Framework:

  • Z listy rozwijanej Klasa modelu wybierz pozycję Movie (MvcMovie.Models).
  • W wierszu Klasy kontekstu danych wybierz znak + (plus).
    • W oknie dialogowym Dodaj Kontekst Danych generowana jest nazwa klasy MvcMovie.Data.MvcMovieContext.
    • Wybierz Dodaj.
  • Na liście rozwijanej Dostawca bazy danych wybierz 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.

Skafold dodaje następujące pakiety:

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

Tworzenie szkieletu powoduje następujące elementy:

  • 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

Szkieletowanie aktualizuje następujące:

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

Automatyczne tworzenie tych plików i aktualizacji plików jest nazywane szkieletowaniem.

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

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

Migracja początkowa

EF Core Uż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 Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console .

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

Add-Migration InitialCreate

  • 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.

Zostanie wyświetlone następujące ostrzeżenie, które zostało rozwiązane w późniejszym kroku:

Nie określono typu przechowywania 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".

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

Update-Database

  • Update-Database: aktualizuje 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.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Core, zobacz EF Core - dokumentację narzędzi PMC w 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.

Note

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż anglojęzyczne, które stosują przecinek (",") jako separator dziesiętny oraz dla formatów dat innych niż amerykańskie, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz this GitHub problem.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W EF Core dostęp do danych odbywa się 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 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; } = default!;
    }
}

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

Wstrzykiwanie zależności

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

W pliku konstruktor używa wstrzykiwania zależności , aby wstrzyknąć 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") ?? throw new InvalidOperationException("Connection string 'MvcMovieContext' not found.")));

System konfiguracji ASP.NET Core odczytuje ciąg połączenia bazy danych "MvcMovieContext".

Sprawdzenie wygenerowanego ciągu połączenia z bazą danych

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

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-4ebefa10-de29-4dea-b2ad-8a8dc6bcf374;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

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

Klasa InitialCreate

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

using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace MvcMovie.Migrations
{
    /// <inheritdoc />
    public partial class InitialCreate : Migration
    {
        /// <inheritdoc />
        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);
                });
        }

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

W przedstawionym wyżej kodzie:

  • 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

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

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Konstruktor używa Dependency Injection, aby wstrzyknąć kontekst bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

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

Przetestuj stronę Edytuj, stronę Szczegóły i stronę Usuwanie.

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku, używając 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 typizowanych obiektów modelu do widoku. Silnie typizowane podejście umożliwia sprawdzanie kodu w czasie kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowany model w klasie MoviesController 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:{PORT}/movies/details/1 ustawia:

  • Kontroler do kontrolera movies, pierwszy segment adresu URL.
  • Działanie dla details, drugiego segmentu adresu URL.
  • id do 1, ostatni segment adresu URL.

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

https://localhost:{PORT}/movies/details?id=1

Parametr id jest definiowany jako typ dopuszczający wartość null (int?) w przypadkach, gdy wartość id nie jest podana.

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, który kontroler przekazał widokowi. Obiekt Model jest silnie typizowany. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor Helperów HTML z DisplayFor silnie typowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok Index.cshtml i metodę Index 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 widoku Index.cshtml kod przechodzi przez filmy za pomocą instrukcji foreach dla silnie typizowanego obiektu Model.

@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>

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

Dodatkowe zasoby

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

Te klasy modeli są używane z 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 są zależne od EF Core. Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku najpierw tworzone są klasy modeli, a następnie EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder Models, dodaj>>. 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ść może mieć wartość null. Aby uzyskać więcej informacji, zobacz Typy referencyjne dopuszczane do wartości null.

Dodawanie pakietów NuGet

Visual Studio automatycznie instaluje wymagane pakiety.

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

Strony filmów szablonowych

Narzędzie do generowania szablonów umożliwia wygenerowanie stron Create, Read, Update i Delete (CRUD) dla modelu filmu.

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

widok powyższego kroku

W oknie dialogowym Dodaj nowy szablonowany element:

  • W okienku po lewej stronie wybierz pozycję Zainstalowane>Common>MVC.
  • Wybierz kontroler MVC z widokami przy użyciu Entity Framework.
  • Wybierz Dodaj.

Dodaj Szkielet - okno dialogowe

Uzupełnij okno dialogowe Dodaj kontroler MVC z widokami, używając Entity Framework:

  • Z listy rozwijanej Klasa modelu wybierz pozycję Movie (MvcMovie.Models).
  • W wierszu Klasy kontekstu danych wybierz znak + (plus).
    • W oknie dialogowym Dodaj Kontekst Danych generowana jest nazwa klasy MvcMovie.Data.MvcMovieContext.
    • Wybierz Dodaj.
  • Na liście rozwijanej Dostawca bazy danych wybierz 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.

Skafold dodaje następujące pakiety:

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

Tworzenie szkieletu powoduje następujące elementy:

  • 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

Szkieletowanie aktualizuje następujące:

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

Automatyczne tworzenie tych plików i aktualizacji plików jest nazywane szkieletowaniem.

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

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

Migracja początkowa

EF Core Uż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 Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console .

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: aktualizuje 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 przechowywania 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 poprzednie ostrzeżenie, zostało naprawione w późniejszym samouczku.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Core, zobacz EF Core - dokumentację narzędzi PMC w 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.

Note

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż anglojęzyczne, które stosują przecinek (",") jako separator dziesiętny oraz dla formatów dat innych niż amerykańskie, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz this GitHub problem.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W EF Core dostęp do danych odbywa się 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 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 zbudowany z użyciem wstrzykiwania zależności (DI). Usługi, takie jak kontekst bazy danych, są rejestrowane przy użyciu DI w Program.cs. Te usługi są udostępniane składnikom, które wymagają ich za pośrednictwem parametrów konstruktora.

W pliku konstruktor używa wstrzykiwania zależności , aby wstrzyknąć 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 ciąg połączenia bazy danych "MvcMovieContext".

Sprawdzenie wygenerowanego ciągu połączenia z bazą danych

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

{
  "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 klucz ConnectionString z pliku appsettings.json.

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");
        }
    }
}

W przedstawionym wyżej kodzie:

  • 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

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

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Konstruktor używa Dependency Injection, aby wstrzyknąć kontekst bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

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

Przetestuj stronę Edytuj, stronę Szczegóły i stronę Usuwanie.

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku, używając 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 typizowanych obiektów modelu do widoku. Silnie typizowane podejście umożliwia sprawdzanie kodu w czasie kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowany model w klasie MoviesController 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 ustawia:

  • Kontroler do kontrolera movies, pierwszy segment adresu URL.
  • Działanie dla details, drugiego segmentu adresu URL.
  • id do 1, ostatni segment 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 dopuszczający wartość null (int?) w przypadkach, gdy wartość id nie jest podana.

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, który kontroler przekazał widokowi. Obiekt Model jest silnie typizowany. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor Helperów HTML z DisplayFor silnie typowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok Index.cshtml i metodę Index 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 widoku Index.cshtml kod przechodzi przez filmy za pomocą instrukcji foreach dla silnie typizowanego obiektu Model.

@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>

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

Dodatkowe zasoby

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

Te klasy modeli są używane z 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 są zależne od EF Core. Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku najpierw tworzone są klasy modeli, a następnie EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder Models, dodaj>>. 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ść może mieć wartość null. Aby uzyskać więcej informacji, zobacz Typy referencyjne dopuszczane do wartości null.

Dodawanie pakietów NuGet

Visual Studio automatycznie instaluje wymagane pakiety.

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

Strony filmów szablonowych

Narzędzie do generowania szablonów umożliwia wygenerowanie stron Create, Read, Update i Delete (CRUD) dla modelu filmu.

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

widok powyższego kroku

W oknie dialogowym Dodaj nowy szablonowany element:

  • W okienku po lewej stronie wybierz pozycję Zainstalowane>Common>MVC.
  • Wybierz kontroler MVC z widokami przy użyciu Entity Framework.
  • Wybierz Dodaj.

Dodaj Szkielet - okno dialogowe

Uzupełnij okno dialogowe Dodaj kontroler MVC z widokami, używając Entity Framework:

  • Z listy rozwijanej Klasa modelu wybierz pozycję Movie (MvcMovie.Models).
  • W wierszu Klasy kontekstu danych wybierz znak + (plus).
    • W oknie dialogowym Dodaj Kontekst Danych generowana jest nazwa klasy MvcMovie.Data.MvcMovieContext.
    • Wybierz Dodaj.
  • Na liście rozwijanej Dostawca bazy danych wybierz 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.

Skafold dodaje następujące pakiety:

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

Tworzenie szkieletu powoduje następujące elementy:

  • 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

Szkieletowanie aktualizuje następujące:

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

Automatyczne tworzenie tych plików i aktualizacji plików jest nazywane szkieletowaniem.

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

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

Migracja początkowa

EF Core Uż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 Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console .

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: aktualizuje 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 poprzednie ostrzeżenie, zostało naprawione w późniejszym samouczku.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Core, zobacz EF Core - dokumentację narzędzi PMC w 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.

Note

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż anglojęzyczne, które stosują przecinek (",") jako separator dziesiętny oraz dla formatów dat innych niż amerykańskie, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz this GitHub problem.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W EF Core dostęp do danych odbywa się 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 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 zbudowany z użyciem wstrzykiwania zależności (DI). Usługi, takie jak kontekst bazy danych, są rejestrowane przy użyciu DI w Program.cs. Te usługi są udostępniane składnikom, które wymagają ich za pośrednictwem parametrów konstruktora.

W pliku konstruktor używa wstrzykiwania zależności , aby wstrzyknąć 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 ciąg połączenia bazy danych "MvcMovieContext".

Sprawdzenie wygenerowanego ciągu połączenia z bazą danych

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

{
  "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 klucz ConnectionString z pliku appsettings.json.

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");
        }
    }
}

W przedstawionym wyżej kodzie:

  • 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

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

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Konstruktor używa Dependency Injection, aby wstrzyknąć kontekst bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

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

Przetestuj stronę Edytuj, stronę Szczegóły i stronę Usuwanie.

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku, używając 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 typizowanych obiektów modelu do widoku. Silnie typizowane podejście umożliwia sprawdzanie kodu w czasie kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowany model w klasie MoviesController 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 ustawia:

  • Kontroler do kontrolera movies, pierwszy segment adresu URL.
  • Działanie dla details, drugiego segmentu adresu URL.
  • id do 1, ostatni segment 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 dopuszczający wartość null (int?) w przypadkach, gdy wartość id nie jest podana.

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, który kontroler przekazał widokowi. Obiekt Model jest silnie typizowany. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor Helperów HTML z DisplayFor silnie typowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok Index.cshtml i metodę Index 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 widoku Index.cshtml kod przechodzi przez filmy za pomocą instrukcji foreach dla silnie typizowanego obiektu Model.

@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>

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

Dodatkowe zasoby

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

Te klasy modeli są używane z 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 są zależne od EF Core. Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku najpierw tworzone są klasy modeli, a następnie EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder Models, dodaj>>. 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ść może mieć wartość null. Aby uzyskać więcej informacji, zobacz Typy referencyjne dopuszczane do wartości null.

Dodawanie pakietów NuGet

Z menu Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console (PMC).

Menu PMC

W PMC uruchom następujące polecenie:

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

Powyższe polecenia dodają:

  • Dostawca EF Core SQL Server. Pakiet dostawczy instaluje pakiet EF Core 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 szablonowych

Narzędzie do generowania szablonów umożliwia wygenerowanie stron Create, Read, Update i Delete (CRUD) dla modelu filmu.

W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Controllers i wybierz 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.

Dodaj Szkielet - okno dialogowe

Uzupełnij okno dialogowe Dodaj kontroler MVC z widokami, używając Entity Framework:

  • Z listy rozwijanej Klasa modelu wybierz pozycję Movie (MvcMovie.Models).
  • W wierszu Klasy kontekstu danych wybierz znak + (plus).
    • W oknie dialogowym Dodaj Kontekst Danych generowana jest nazwa klasy MvcMovie.Data.MvcMovieContext.
    • 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.

Szkieletowanie aktualizuje następujące:

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

Tworzenie szkieletu powoduje następujące elementy:

  • 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 szkieletowaniem.

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

Tworzenie aplikacji

Kompilowanie aplikacji. Kompilator wygeneruje kilka ostrzeżeń dotyczących obsługiwania wartości null. Aby uzyskać więcej informacji, zobacz to zgłoszenie na GitHubie i Nullable reference types.

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 Core Uż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 Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console .

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: aktualizuje 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 poprzednie ostrzeżenie, zostało naprawione w późniejszym samouczku.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Core, zobacz EF Core - dokumentację narzędzi PMC w 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.

Note

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż anglojęzyczne, które stosują przecinek (",") jako separator dziesiętny oraz dla formatów dat innych niż amerykańskie, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz this GitHub problem.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W EF Core dostęp do danych odbywa się 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 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 zbudowany z użyciem wstrzykiwania zależności (DI). Usługi, takie jak kontekst bazy danych, są rejestrowane przy użyciu DI w Program.cs. Te usługi są udostępniane składnikom, które wymagają ich za pośrednictwem parametrów konstruktora.

W pliku konstruktor używa wstrzykiwania zależności , aby wstrzyknąć 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 ciąg połączenia bazy danych "MvcMovieContext".

Sprawdzenie wygenerowanego ciągu połączenia z bazą danych

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

{
  "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 klucz ConnectionString z pliku appsettings.json.

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");
        }
    }
}

W przedstawionym wyżej kodzie:

  • 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

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

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Konstruktor używa Dependency Injection, aby wstrzyknąć kontekst bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

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

Przetestuj stronę Edytuj, stronę Szczegóły i stronę Usuwanie.

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku, używając 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 typizowanych obiektów modelu do widoku. Silnie typizowane podejście umożliwia sprawdzanie kodu w czasie kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowany model w klasie MoviesController 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 ustawia:

  • Kontroler do kontrolera movies, pierwszy segment adresu URL.
  • Działanie dla details, drugiego segmentu adresu URL.
  • id do 1, ostatni segment 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 dopuszczający wartość null (int?) w przypadkach, gdy wartość id nie jest podana.

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, który kontroler przekazał widokowi. Obiekt Model jest silnie typizowany. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor Helperów HTML z DisplayFor silnie typowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok Index.cshtml i metodę Index 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 widoku Index.cshtml kod przechodzi przez filmy za pomocą instrukcji foreach dla silnie typizowanego obiektu Model.

@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>

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

Dodatkowe zasoby

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

Te klasy modeli są używane z 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 są zależne od EF Core. Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku najpierw tworzone są klasy modeli, a następnie EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder Models, dodaj>>. 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 Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console (PMC).

Menu PMC

W PMC uruchom następujące polecenie:

Install-Package Microsoft.EntityFrameworkCore.Design

Powyższe polecenia dodają:

  • Dostawca EF Core SQL Server. Pakiet dostawczy instaluje pakiet EF Core 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 szablonowych

Narzędzie do generowania szablonów umożliwia wygenerowanie stron Create, Read, Update i Delete (CRUD) dla modelu filmu.

W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Controllers i wybierz 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.

Dodaj Szkielet - okno dialogowe

Uzupełnij okno dialogowe Dodaj kontroler MVC z widokami, używając Entity Framework:

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

Dodaj kontekst danych zachowaj wartości domyślne

Szkieletowanie aktualizuje następujące:

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

Tworzenie szkieletu powoduje następujące elementy:

  • 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 generowaniem szkieletów.

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

Migracja początkowa

EF Core Uż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 Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console .

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: aktualizuje 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 poprzednie ostrzeżenie, zostało naprawione w późniejszym samouczku.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Core, zobacz EF Core - dokumentację narzędzi PMC w 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.

Note

W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż anglojęzyczne, które stosują przecinek (",") jako separator dziesiętny oraz dla formatów dat innych niż amerykańskie, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz this GitHub problem.

Sprawdzanie wygenerowanej klasy kontekstu bazy danych i rejestracji

W EF Core dostęp do danych odbywa się 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 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 zbudowany z użyciem wstrzykiwania zależności (DI). Usługi, takie jak kontekst bazy danych, muszą być zarejestrowane przy użyciu DI w Startup. Składniki, które wymagają tych usług, są dostarczane za pomocą parametrów konstruktora.

W pliku konstruktor używa wstrzykiwania zależności , aby wstrzyknąć 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 ciąg połączenia bazy danych "MvcMovieContext".

Sprawdzenie wygenerowanego ciągu połączenia z bazą danych

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

{
  "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 klucz ConnectionString z pliku appsettings.json.

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");
    }
}

W przedstawionym wyżej kodzie:

  • 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

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

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Konstruktor używa Dependency Injection, aby wstrzyknąć kontekst bazy danych (MvcMovieContext) do kontrolera. Kontekst bazy danych jest używany w każdej z metod CRUD w kontrolerze.

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

Przetestuj stronę Edytuj, stronę Szczegóły i stronę Usuwanie.

Silnie typizowane modele i @model dyrektywa

Wcześniej w tym samouczku pokazano, jak kontroler może przekazywać dane lub obiekty do widoku, używając 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 typizowanych obiektów modelu do widoku. Silnie typizowane podejście umożliwia sprawdzanie kodu w czasie kompilacji. Mechanizm tworzenia szkieletów przekazał silnie typizowany model w klasie MoviesController 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 ustawia:

  • Kontroler do kontrolera movies, pierwszy segment adresu URL.
  • Działanie dla details, drugiego segmentu adresu URL.
  • id do 1, ostatni segment 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 dopuszczający wartość null (int?) w przypadkach, gdy wartość id nie jest podana.

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, który kontroler przekazał widokowi. Obiekt Model jest silnie typizowany. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor Helperów HTML z DisplayFor silnie typowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok Index.cshtml i metodę Index 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 widoku Index.cshtml kod przechodzi przez filmy za pomocą instrukcji foreach dla silnie typizowanego obiektu Model.

@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>

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

Logowanie SQL w 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 pliku appsettings.Development.json:

{
  "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": "*"
}

Z użyciem poprzedniego JSON instrukcje SQL są wyświetlane w wierszu poleceń i w oknie wyjściowym Visual Studio.

Aby uzyskać więcej informacji, zobacz następujące zasoby:

Dodatkowe zasoby

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

Te klasy modeli są używane z 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 są zależne od EF Core. Definiują tylko właściwości danych, które mają być przechowywane w bazie danych.

W tym samouczku najpierw tworzone są klasy modeli, a następnie EF Core tworzy bazę danych.

Dodawanie klasy modelu danych

Kliknij prawym przyciskiem myszy folder Models, dodaj>>. 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 Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console (PMC).

Menu PMC

W PMC uruchom następujące polecenie:

Install-Package Microsoft.EntityFrameworkCore.SqlServer

Poprzednie polecenie dodaje dostawcę EF Core SQL Server. Pakiet dostawczy instaluje pakiet EF Core 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 zbudowany z użyciem 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 pokazany później w samouczku. W tej sekcji zarejestrujesz kontekst bazy danych w kontenerze DI.

Dodaj następujące using instrukcje na górze 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 obiekcie DbContextOptions. W przypadku programowania lokalnego system konfiguracji ASP.NET Core odczytuje parametry połączenia z pliku appsettings.json.

Zbadaj ciąg połączenia bazy danych

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

{
  "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 szablonowych

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

W Eksplorator rozwiązań kliknij prawym przyciskiem myszy Controllers folder > 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.

Dodaj Szkielet - okno dialogowe

Wypełnij okno dialogu Dodawanie kontrolera:

  • Klasa modelu:Movie (MvcMovie.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

Visual Studio tworzy:

  • Kontroler filmów (Controllers/MoviesController.cs)
  • Razor wyświetl pliki dla stron Utwórz, Usuń, Szczegóły, Edytuj i Indeks (*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: Movie.

Migracja początkowa

EF Core Uż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 Tools wybierz pozycję NuGet Menedżer pakietów>Menedżer pakietów Console (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: aktualizuje 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()".

    Można zignorować to ostrzeżenie, zostanie ono rozwiązane w kolejnych samouczkach.

Aby uzyskać więcej informacji na temat narzędzi PMC dla EF Core, zobacz EF Core - dokumentację narzędzi PMC w Visual Studio.

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>(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 Movie App.

    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 etap migracji.

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

    Note

    W polu może nie być możliwe wprowadzenie przecinków dziesiętnych Price . Aby obsługiwać walidację jQuery dla ustawień regionalnych innych niż anglojęzyczne, które stosują przecinek (",") jako separator dziesiętny oraz dla formatów dat innych niż amerykańskie, aplikacja musi zostać zglobalizowana. Aby uzyskać instrukcje dotyczące globalizacji, zobacz this GitHub problem.

  • Przetestuj stronę Edytuj, stronę Szczegóły i stronę Usuwanie.

Wstrzykiwanie zależności w kontrolerze

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

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

Konstruktor używa Dependency Injection, aby wstrzyknąć kontekst 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, używając 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 typizowanych obiektów modelu do widoku. Silnie typizowane podejście umożliwia sprawdzanie kodu w czasie 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 zestawy https://localhost:5001/movies/details/1:

  • 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 nullable (int?) w przypadku, gdy nie podano wartości identyfikatora.

Wyrażenie lambda jest przekazywane do FirstOrDefaultAsync, aby 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, który kontroler przekazał widokowi. Obiekt Model jest silnie typizowany. Na przykład w Details.cshtml widoku kod przekazuje każde pole filmu do DisplayNameFor Helperów HTML z DisplayFor silnie typowanym Model obiektem. Metody Create i Edit oraz widoki również przekazują Movie obiekt modelu.

Sprawdź widok Index.cshtml i metodę Index 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, które kontroler przekazał do widoku, przy użyciu silnie typizowanego obiektu Model. Na przykład w widoku Index.cshtml kod przechodzi przez filmy za pomocą instrukcji foreach dla silnie typizowanego obiektu Model.

@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>

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

Dodatkowe zasoby