Partilhar via


Parte 4, adicionar um modelo a um aplicativo ASP.NET Core MVC

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.

Advertência

Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.

Importante

Estas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece garantias, expressas ou implícitas, em relação às informações fornecidas aqui.

Para a versão atual, consulte a versão .NET 9 deste artigo.

Por Rick Anderson e Jon P Smith.

Neste tutorial, as classes são adicionadas para gerenciar filmes em um banco de dados. Estas classes são a parte "Model" da aplicação MVC.

Essas classes de modelo são usadas com Entity Framework Core (EF Core) para trabalhar com um banco de dados. EF Core é uma estrutura de mapeamento objeto-relacional (ORM) que simplifica o código de acesso a dados que você precisa escrever.

As classes de modelo criadas são conhecidas como classes POCO, de Plain Old CLR Objects. As classes POCO não têm qualquer dependência de EF Core. Eles apenas definem as propriedades dos dados a serem armazenados no banco de dados.

Neste tutorial, as classes de modelo são criadas primeiro e EF Core cria o banco de dados.

Adicionar uma classe de modelo de dados

Clique com o botão direito do rato na pasta Modelos>Adicionar>Classe. Nomeie o arquivo Movie.cs.

Atualize o arquivo Models/Movie.cs com o seguinte código:

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

A classe Movie contém um campo Id, que é exigido pelo banco de dados para a chave primária.

O atributo DataType em ReleaseDate especifica o tipo de dados (Date). Com este atributo:

  • O usuário não é obrigado a inserir informações de hora no campo de data.
  • Apenas a data é exibida, não as informações de hora.

DataAnnotations são abordados em um tutorial posterior.

O ponto de interrogação após string indica que a propriedade é anulável. Para obter mais informações, consulte Tipos de referência anuláveis.

Adicionar pacotes NuGet

O Visual Studio instala automaticamente os pacotes necessários.

Construa o projeto como uma verificação de erros do compilador.

Páginas de filmes em andaimes

Use a ferramenta de scaffolding para produzir páginas Create, Read, Updatee Delete (CRUD) para o modelo de filme.

No Explorador de Soluções , clique com o botão direito na pasta Controladores e selecione Adicionar > Novo Item Estruturado.

vista da etapa acima

Na caixa de diálogo Adicionar Novo Item Andaime:

  • No painel esquerdo, selecione Installed>Common>MVC.
  • Selecione controlador MVC com exibições, usando o Entity Framework.
  • Selecione Adicionar.

Caixa de Diálogo Adicionar Scaffold

Conclua o Adicionar Controlador MVC com modos de exibição, usando a caixa de diálogo do Entity Framework:

  • Na lista suspensa da classe Model , selecione Filme (MvcMovie.Models).
  • Na linha da classe de contexto de dados, selecione o sinal de + (mais).
    • Na caixa de diálogo Adicionar Contexto de Dados , o nome da classe MvcMovie.Data.MvcMovieContext é gerado.
    • Selecione Adicionar.
  • Na lista suspensa Provedor de banco de dados, selecione SQL Server.
  • Visualizações e nome do controlador: Mantenha o padrão.
  • Selecione Adicionar.

Adicionar contexto de dados manter os padrões

Se receber uma mensagem de erro, selecione Adicionar uma segunda vez para tentar novamente.

Andaimes adiciona os seguintes pacotes:

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

O andaime cria o seguinte:

  • Um controlador de filmes: Controllers/MoviesController.cs
  • Razor visualizar arquivos para Criar, Excluir, Detalhes, Editare Índice páginas: Views/Movies/*.cshtml
  • Uma classe de contexto de banco de dados: Data/MvcMovieContext.cs

O andaime atualiza o seguinte:

  • Insere as referências de pacote necessárias no arquivo de projeto MvcMovie.csproj.
  • Registra o contexto do banco de dados no arquivo Program.cs.
  • Adiciona uma cadeia de conexão de banco de dados ao arquivo appsettings.json.

A criação automática desses arquivos e a atualização dos mesmos é conhecida como scaffolding.

As páginas com andaimes ainda não podem ser usadas porque o banco de dados não existe. Executar a aplicação e selecionar o link Movie App resulta numa mensagem de erro Não é possível abrir o banco de dados ou nenhuma tabela: Movie.

Crie o aplicativo para verificar se não há erros.

Migração inicial

Utilize a funcionalidade EF CoreMigrações para criar a base de dados. de Migrações é um conjunto de ferramentas que criam e atualizam um banco de dados para corresponder ao modelo de dados.

No menu Ferramentas, selecione Gestor de Pacotes NuGet>Consola do Gestor de Pacotes.

No Console do Gerenciador de Pacotes (PMC), digite o seguinte comando:

Add-Migration InitialCreate

  • Add-Migration InitialCreate: Gera um arquivo de migração Migrations/{timestamp}_InitialCreate.cs. O argumento InitialCreate é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, é selecionado um nome que descreve a migração. Como esta é a primeira migração, a classe gerada contém código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classe MvcMovieContext.

O seguinte aviso é exibido, que é abordado em uma etapa posterior:

Não foi especificado um tipo de armazenamento para a propriedade decimal 'Preço' no tipo de entidade 'Filme'. Isso fará com que os valores sejam truncados silenciosamente se não se ajustarem à precisão e escala padrão. Especifique explicitamente o tipo de coluna do servidor SQL que pode acomodar todos os valores em 'OnModelCreating' usando 'HasColumnType', especifique precisão e escala usando 'HasPrecision' ou configure um conversor de valores usando 'HasConversion'.

No PMC, digite o seguinte comando:

Update-Database

  • Update-Database: Atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Este comando executa o método Up no arquivo Migrations/{time-stamp}_InitialCreate.cs, que cria o banco de dados.

Para obter mais informações sobre as ferramentas PMC para EF Core, consulte a Referência de Ferramentas EF Core - PMC no Visual Studio.

Testar a aplicação

Execute a aplicação e selecione o link do Movie App.

Se obtiveres uma exceção semelhante à seguinte, talvez tenhas perdido o comando Update-Database na etapa de migrações :

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

Observação

Talvez não seja possível inserir vírgulas decimais no campo Price. Para oferecer suporte a de validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e para formatos de data não US-English, o aplicativo deve ser globalizado. Para obter instruções sobre globalização, consulte esta questão do GitHub.

Examine a classe de contexto e o registro do banco de dados gerado

Com EF Core, o acesso aos dados é realizado usando um modelo. Um modelo é composto de classes de entidade e um objeto de contexto que representa uma sessão com o banco de dados. O objeto de contexto permite consultar e salvar dados. O contexto do banco de dados é derivado de Microsoft.EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.

Scaffolding cria a classe de contexto de banco de dados Data/MvcMovieContext.cs:

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!;
    }
}

O código anterior cria uma propriedade DbSet<Movie> que representa os filmes no banco de dados.

Injeção de dependência

ASP.NET Core é construído com injeção de dependência (DI). Serviços, como o contexto do banco de dados, são registrados com DI em Program.cs. Esses serviços são fornecidos a componentes que os exigem por meio de parâmetros do construtor.

No arquivo Controllers/MoviesController.cs, o construtor usa Dependency Injection para injetar o contexto de banco de dados MvcMovieContext no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Andaime gerou o seguinte código destacado em 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.")));

O sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".

Examinar a string de conexão de base de dados gerada

Scaffolding adicionou uma cadeia de conexão ao arquivo 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"
  }
}

Para o desenvolvimento local, o sistema de configuração ASP.NET Core lê a chave ConnectionString do arquivo appsettings.json.

A classe InitialCreate

Examine o arquivo de migração Migrations/{timestamp}_InitialCreate.cs:

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

No código anterior:

  • InitialCreate.Up cria a tabela Filme e configura Id como a chave primária.
  • InitialCreate.Down reverte as alterações de esquema feitas pela migração de Up.

Injeção de dependência no controlador

Abra o ficheiro Controllers/MoviesController.cs e examine o construtor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

O construtor usa Dependency Injection para injetar o contexto do banco de dados (MvcMovieContext) no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Teste a página Criar. Insira e envie dados.

Teste as páginas Editar, Detalhese Eliminar.

Modelos fortemente tipificados e a diretiva @model

No início deste tutorial, você viu como um controlador pode passar dados ou objetos para uma exibição usando o dicionário ViewData. O dicionário ViewData é um objeto dinâmico que fornece uma maneira conveniente e tardia de passar informações para uma exibição.

O MVC fornece a capacidade de passar objetos de modelo fortemente tipados para uma exibição. Esta abordagem fortemente tipada permite a verificação de código em tempo de compilação. O mecanismo de andaime passou por um modelo fortemente tipado na classe MoviesController e visualizações.

Examine o método Details gerado no arquivo Controllers/MoviesController.cs:

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

O parâmetro id geralmente é passado como dados de rota. Por exemplo, https://localhost:5001/movies/details/1 define:

  • O controlador que aponta para o controlador movies, o primeiro segmento de URL.
  • A ação para details, o segundo segmento de URL.
  • O id a 1, o último segmento de URL.

O id pode ser passado com uma cadeia de caracteres de consulta, como no exemplo a seguir:

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

O parâmetro id é definido como um tipo anulável (int?) nos casos em que o valor id não é fornecido.

Um de expressão lambda é passado para o método FirstOrDefaultAsync para selecionar entidades de filme que correspondam aos dados de rota ou ao valor da cadeia de caracteres de consulta.

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

Se um filme for encontrado, uma instância do modelo Movie será passada para a visualização Details:

return View(movie);

Examine o conteúdo do arquivo Views/Movies/Details.cshtml:

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

A instrução @model na parte superior do arquivo de visualização especifica o tipo de objeto que a visualização espera. Quando o controlador de filme foi criado, a seguinte instrução @model foi incluída:

@model MvcMovie.Models.Movie

Esta diretiva @model permite o acesso ao filme que o controlador passou para a visualização. O objeto Model é fortemente tipado. Por exemplo, na visualização Details.cshtml, o código passa cada campo de filme para os auxiliares de HTML DisplayNameFor e DisplayFor usando o objeto Model fortemente tipado. Os métodos e exibições Create e Edit também passam por um objeto de modelo Movie.

Examine a visualização Index.cshtml e o método Index no controlador Movies. Observe como o código cria um objeto List quando chama o método View. O código passa essa lista de Movies do método de ação Index para a exibição:

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

O código retorna detalhes do problema se a propriedade Movie do contexto de dados for nulo.

Quando o controlador de filmes foi criado, o andaime incluía a seguinte instrução @model na parte superior do arquivo Index.cshtml:

@model IEnumerable<MvcMovie.Models.Movie>

A diretiva @model permite o acesso à lista de filmes que o controlador passou para a visualização usando um objeto Model fortemente digitado. Por exemplo, na visualização Index.cshtml, o código percorre os filmes com uma instrução foreach sobre o objeto Model fortemente tipado:

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

Como o objeto Model é fortemente tipado como um objeto IEnumerable<Movie>, cada item no loop é tipado como Movie. Entre outros benefícios, o compilador valida os tipos usados no código.

Recursos adicionais

Neste tutorial, as classes são adicionadas para gerenciar filmes em um banco de dados. Estas classes são a parte "Model" da aplicação MVC.

Essas classes de modelo são usadas com Entity Framework Core (EF Core) para trabalhar com um banco de dados. EF Core é uma estrutura de mapeamento objeto-relacional (ORM) que simplifica o código de acesso a dados que você precisa escrever.

As classes de modelo criadas são conhecidas como classes POCO , de Plain Old CLR Objects. As classes POCO não têm qualquer dependência de EF Core. Eles apenas definem as propriedades dos dados a serem armazenados no banco de dados.

Neste tutorial, as classes de modelo são criadas primeiro e EF Core cria o banco de dados.

Adicionar uma classe de modelo de dados

Clique com o botão direito do rato na pasta Modelos>Adicionar>Classe. Nomeie o arquivo Movie.cs.

Atualize o arquivo Models/Movie.cs com o seguinte código:

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

A classe Movie contém um campo Id, que é exigido pelo banco de dados para a chave primária.

O atributo DataType em ReleaseDate especifica o tipo de dados (Date). Com este atributo:

  • O usuário não é obrigado a inserir informações de hora no campo de data.
  • Apenas a data é exibida, não as informações de hora.

DataAnnotations são abordados em um tutorial posterior.

O ponto de interrogação após string indica que a propriedade é anulável. Para obter mais informações, consulte Tipos de referência anuláveis.

Adicionar pacotes NuGet

O Visual Studio instala automaticamente os pacotes necessários.

Construa o projeto como uma verificação de erros do compilador.

Páginas de filmes em andaimes

Use a ferramenta de scaffolding para produzir as páginas Create, Read, Updatee Delete (CRUD) para o modelo de filme.

No Explorador de Soluções, clique com o botão direito do rato na pasta Controladores e selecione Adicionar Novo Item Estruturado >.

vista da etapa acima

Na caixa de diálogo Adicionar Novo Item Andaime:

  • No painel esquerdo, selecione Instalado>Comum>MVC.
  • Selecione controlador MVC com vistas, usando Entity Framework.
  • Selecione Adicionar.

adicionar caixa de diálogo de andaime

Conclua o Adicionar Controlador MVC com modos de exibição, usando a caixa de diálogo do Entity Framework:

  • Na lista suspensa classe Model, selecione Filme (MvcMovie.Models).
  • Na linha da classe de contexto de Dados, selecione o sinal + (mais).
    • Na caixa de diálogo Adicionar Contexto de Dados, é gerado o nome da classe MvcMovie.Data.MvcMovieContext.
    • Selecione Adicionar.
  • Na lista suspensa Provedor de banco de dados, selecione SQL Server.
  • Visualizações e Nome do Controlador: Mantenha como predefinido.
  • Selecione Adicionar.

Adicionar contexto de dados manter os padrões

Se receber uma mensagem de erro, selecione Adicionar uma segunda vez para tentar novamente.

Andaimes adiciona os seguintes pacotes:

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

O andaime cria o seguinte:

  • Um controlador de filmes: Controllers/MoviesController.cs
  • Razor visualizar arquivos para Criar, Eliminar, Detalhes, Editare Índice de páginas: Views/Movies/*.cshtml
  • Uma classe de contexto de banco de dados: Data/MvcMovieContext.cs

O andaime atualiza o seguinte:

  • Insere as referências de pacote necessárias no arquivo de projeto MvcMovie.csproj.
  • Registra o contexto do banco de dados no arquivo Program.cs.
  • Adiciona uma cadeia de conexão de banco de dados ao arquivo appsettings.json.

A criação automática desses arquivos e atualizações de arquivos é conhecida como scaffolding.

As páginas com andaimes ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link do Movie App resulta numa mensagem de erro Não é possível abrir o banco de dados ou não existe tal tabela: Movie.

Crie o aplicativo para verificar se não há erros.

Migração inicial

Use o recurso EF CoreMigrações para criar a base de dados. Migrações é um conjunto de ferramentas que criam e atualizam uma base de dados para corresponder ao modelo de dados.

No menu Ferramentas, selecione Gestor de Pacotes NuGet>Consola do Gestor de Pacotes.

No Console do Gerenciador de Pacotes (PMC), digite os seguintes comandos:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Gera um arquivo de migração Migrations/{timestamp}_InitialCreate.cs. O argumento InitialCreate corresponde ao nome da migração. Qualquer nome pode ser usado, mas, por convenção, é selecionado um nome que descreve a migração. Como esta é a primeira migração, a classe gerada contém código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classe MvcMovieContext.

  • Update-Database: Atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Este comando executa o método Up no arquivo Migrations/{time-stamp}_InitialCreate.cs, que cria o banco de dados.

O comando Update-Database gera o seguinte aviso:

Nenhum tipo de loja foi especificado para a propriedade decimal 'Price' no tipo de entidade 'Movie'. Isso fará com que os valores sejam truncados silenciosamente se não se ajustarem à precisão e escala padrão. Especifique explicitamente o tipo de coluna do servidor SQL que pode acomodar todos os valores em 'OnModelCreating' usando 'HasColumnType', especifique precisão e escala usando 'HasPrecision' ou configure um conversor de valores usando 'HasConversion'.

Ignore o aviso anterior, ele é corrigido em um tutorial posterior.

Para obter mais informações sobre as ferramentas PMC para EF Core, consulte a referência de ferramentas EF Core - PMC no Visual Studio.

Testar a aplicação

Execute a aplicação e selecione o link Movie App.

Se obtiveres uma exceção semelhante à seguinte, talvez tenhas perdido o comando Update-Database na etapa de migrações :

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

Observação

Talvez não seja possível inserir vírgulas decimais no campo Price. Para oferecer suporte à validação do jQuery para locais que não sejam de língua inglesa e que usem a vírgula (",") como ponto decimal, assim como para formatos de data que não sejam US-English, é necessário que o aplicativo seja internacionalizado. Para obter instruções sobre globalização, consulte este issue do GitHub .

Examine a classe de contexto e o registro do banco de dados gerado

Com EF Core, o acesso aos dados é realizado usando um modelo. Um modelo é composto de classes de entidade e um objeto de contexto que representa uma sessão com o banco de dados. O objeto de contexto permite consultar e salvar dados. O contexto do banco de dados é derivado de Microsoft.EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.

Scaffolding cria a classe de contexto de banco de dados Data/MvcMovieContext.cs:

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

O código anterior cria uma propriedade DbSet<Movie> que representa os filmes no banco de dados.

Injeção de dependência

ASP.NET Core é construído com injeção de dependência (DI). Serviços, como o contexto do banco de dados, são registrados com DI em Program.cs. Esses serviços são fornecidos a componentes que os exigem por meio de parâmetros do construtor.

No arquivo Controllers/MoviesController.cs, o construtor usa Dependency Injection para injetar o contexto de banco de dados MvcMovieContext no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Scaffolding gerou o seguinte código realçado em Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

O do sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".

Analisar a cadeia de conexão da base de dados gerada

Scaffolding adicionou uma cadeia de conexão ao arquivo appsettings.json:

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

Para o desenvolvimento local, o sistema de configuração ASP.NET Core lê a chave ConnectionString do arquivo appsettings.json.

A classe InitialCreate

Examine o arquivo de migração Migrations/{timestamp}_InitialCreate.cs:

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

No código anterior:

  • InitialCreate.Up cria a tabela Filme e configura Id como a chave primária.
  • InitialCreate.Down reverte as alterações de esquema feitas pela migração de Up.

Injeção de dependência no controlador

Abra o arquivo Controllers/MoviesController.cs e examine o construtor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

O construtor usa Dependency Injection para injetar o contexto do banco de dados (MvcMovieContext) no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD dentro do controlador.

Teste a página Criar. Insira e envie dados.

Teste as páginas Editar, Detalhese Eliminar.

Modelos fortemente tipificados e a diretiva @model

No início deste tutorial, você viu como um controlador pode passar dados ou objetos para uma exibição usando o dicionário ViewData. O dicionário ViewData é um objeto dinâmico que fornece uma maneira conveniente e tardia de passar informações para uma exibição.

O MVC fornece a capacidade de passar objetos de modelo fortemente tipados para uma exibição. Essa abordagem fortemente tipada permite a verificação de código durante a compilação. O mecanismo de andaime passou por um modelo fortemente tipado na classe MoviesController e visualizações.

Examine o método Details gerado no arquivo Controllers/MoviesController.cs:

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

O parâmetro id geralmente é passado como dados de rota. Por exemplo, o https://localhost:5001/movies/details/1 define:

  • O controlador para o movies, o primeiro segmento de URL.
  • A ação para details, o segundo segmento de URL.
  • Do id até 1, o último segmento de URL.

O id pode ser passado com uma cadeia de caracteres de consulta, como no exemplo a seguir:

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

O parâmetro id é definido como um tipo anulável (int?) nos casos em que o valor id não é fornecido.

Um de expressão lambda é passado para o método FirstOrDefaultAsync para selecionar entidades de filme que correspondam aos dados de rota ou ao valor da cadeia de caracteres de consulta.

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

Se um filme for encontrado, uma instância do modelo Movie será passada para a visualização Details:

return View(movie);

Examine o conteúdo do arquivo Views/Movies/Details.cshtml:

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

A instrução @model na parte superior do arquivo de vista especifica o tipo de objeto que a vista espera. Quando o controlador de filme foi criado, a seguinte instrução @model foi incluída:

@model MvcMovie.Models.Movie

Esta diretiva @model permite o acesso ao filme que o controlador passou para a vista. O objeto Model é fortemente tipado. Por exemplo, na visualização Details.cshtml, o código passa cada campo de filme para os HTML Helpers DisplayNameFor e DisplayFor com o objeto Model fortemente tipado. Os métodos e exibições Create e Edit também passam por um objeto de modelo Movie.

Examine a exibição Index.cshtml e o método Index no controlador de filmes. Observe como o código cria um objeto List quando chama o método View. O código passa essa lista de Movies do método de ação Index para a exibição:

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

O código retorna detalhes do problema se a propriedade Movie do contexto de dados for null.

Quando o controlador de filmes foi criado, o scaffolding incluiu a seguinte instrução @model na parte superior do arquivo Index.cshtml:

@model IEnumerable<MvcMovie.Models.Movie>

A diretiva @model permite o acesso à lista de filmes que o controlador passou para a visualização usando um objeto Model fortemente digitado. Por exemplo, na visualização Index.cshtml, o código percorre os filmes com uma instrução foreach sobre o objeto Model fortemente tipado:

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

Como o objeto Model é fortemente tipado como um objeto IEnumerable<Movie>, cada item no loop está tipado como Movie. Entre outros benefícios, o compilador valida os tipos usados no código.

Recursos adicionais

Neste tutorial, as classes são adicionadas para gerenciar filmes em um banco de dados. Estas classes são a parte "Model" da aplicação MVC.

Essas classes de modelo são usadas com Entity Framework Core (EF Core) para trabalhar com um banco de dados. EF Core é uma estrutura de mapeamento objeto-relacional (ORM) que simplifica o código de acesso a dados que você precisa escrever.

As classes de modelo criadas são conhecidas como classes POCO, de Plain Old CLR Objects. As classes POCO não têm qualquer dependência de EF Core. Eles apenas definem as propriedades dos dados a serem armazenados no banco de dados.

Neste tutorial, as classes de modelo são criadas primeiro e EF Core cria o banco de dados.

Adicionar uma classe de modelo de dados

Clique com o botão direito do rato na pasta Modelos>Adicionar>Classe. Nomeie o arquivo Movie.cs.

Atualize o arquivo Models/Movie.cs com o seguinte código:

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

A classe Movie contém um campo Id, que é exigido pelo banco de dados para a chave primária.

O atributo DataType em ReleaseDate especifica o tipo de dados (Date). Com este atributo:

  • O usuário não é obrigado a inserir informações de hora no campo de data.
  • Apenas a data é exibida, não as informações de hora.

DataAnnotations são abordados em um tutorial posterior.

O ponto de interrogação após string indica que a propriedade é anulável. Para obter mais informações, consulte Tipos de referência anuláveis.

Adicionar pacotes NuGet

O Visual Studio instala automaticamente os pacotes necessários.

Construa o projeto como uma verificação de erros do compilador.

Páginas de filmes em andaimes

Utilize a ferramenta de scaffolding para produzir páginas Create, Read, Updatee Delete (CRUD) para o modelo de filme.

No Explorador de Soluções , clicar com o botão direito na pasta Controladores e selecionar Adicionar > Novo Item com Estrutura de Suporte.

vista da etapa acima

Na caixa de diálogo Adicionar Novo Item Andaime:

  • No painel esquerdo, selecione Instalado>Comum>MVC.
  • Selecione controlador MVC com vistas, usando Entity Framework.
  • Selecione Adicionar.

caixa de diálogo Adicionar Estrutura

Conclua o Adicionar Controlador MVC com modos de exibição, usando a caixa de diálogo do Entity Framework:

  • Na lista suspensa da classe Model, selecione Filme (MvcMovie.Models).
  • Na linha da classe de contexto de Dados, selecione o sinal + (mais).
    • Na caixa de diálogo Adicionar Contexto de Dados , o nome da classe MvcMovie.Data.MvcMovieContext é gerado.
    • Selecione Adicionar.
  • Na lista suspensa Provedor de banco de dados, selecione SQL Server.
  • Visualizações e nome do controlador : Mantenha o padrão.
  • Selecione Adicionar.

Adicionar contexto de dados manter os padrões Se você receber uma mensagem de erro, selecione Adicionar segunda vez para tentar novamente.

Andaimes adiciona os seguintes pacotes:

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

O andaime cria o seguinte:

  • Um controlador de filmes: Controllers/MoviesController.cs
  • Razor visualizar arquivos para Criar, Excluir, Detalhes, Editare Índice páginas: Views/Movies/*.cshtml
  • Uma classe de contexto de banco de dados: Data/MvcMovieContext.cs

O andaime atualiza o seguinte:

  • Insere as referências de pacote necessárias no arquivo de projeto MvcMovie.csproj.
  • Registra o contexto do banco de dados no arquivo Program.cs.
  • Adiciona uma cadeia de conexão de banco de dados ao arquivo appsettings.json.

A criação automática desses arquivos e atualizações de arquivos é conhecida como scaffolding.

As páginas com andaimes ainda não podem ser usadas porque o banco de dados não existe. Executar a aplicação e selecionar o link Movie App resulta numa mensagem de erro Não é possível abrir o banco de dados ou nenhuma tabela: Movie.

Crie o aplicativo para verificar se não há erros.

Migração inicial

Use a funcionalidade EF CoreMigrações para criar a base de dados. Migrações é um conjunto de ferramentas que cria e atualiza uma base de dados para corresponder ao modelo de dados.

No menu Ferramentas, selecione Gestor de Pacotes NuGet>Consola do Gestor de Pacotes .

No Console do Gerenciador de Pacotes (PMC), digite os seguintes comandos:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Gera um arquivo de migração Migrations/{timestamp}_InitialCreate.cs. O argumento InitialCreate é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, é selecionado um nome que descreve a migração. Como esta é a primeira migração, a classe gerada contém código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classe MvcMovieContext.

  • Update-Database: Atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Este comando executa o método Up no arquivo Migrations/{time-stamp}_InitialCreate.cs, que cria o banco de dados.

O comando Update-Database gera o seguinte aviso:

Nenhum tipo foi especificado para a coluna decimal 'Preço' no tipo de entidade 'Filme'. Isso fará com que os valores sejam truncados silenciosamente se não se ajustarem à precisão e escala padrão. Especifique explicitamente o tipo de coluna do servidor SQL que pode acomodar todos os valores usando 'HasColumnType()'.

Ignore o aviso anterior, ele é corrigido em um tutorial posterior.

Para obter mais informações sobre as ferramentas PMC para EF Core, consulte a referência de ferramentas EF Core - PMC no Visual Studio.

Testar a aplicação

Execute a aplicação e, em seguida, selecione o link Movie App.

Se obtiveres uma exceção semelhante à seguinte, talvez tenhas perdido o comando Update-Database na etapa das migrações:

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

Observação

Talvez não seja possível inserir vírgulas decimais no campo Price. Para oferecer suporte a de validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e para formatos de data não US-English, o aplicativo deve ser globalizado. Para obter instruções sobre globalização, consulte este tópico do GitHub .

Examine a classe de contexto e o registro do banco de dados gerado

Com EF Core, o acesso aos dados é realizado usando um modelo. Um modelo é composto de classes de entidade e um objeto de contexto que representa uma sessão com o banco de dados. O objeto de contexto permite consultar e salvar dados. O contexto do banco de dados é derivado de Microsoft.EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.

Scaffolding cria a classe de contexto de banco de dados Data/MvcMovieContext.cs:

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

O código anterior cria uma propriedade DbSet<Movie> que representa os filmes no banco de dados.

Injeção de dependência

ASP.NET Core é construído com injeção de dependência (DI). Serviços, como o contexto do banco de dados, são registrados com DI em Program.cs. Esses serviços são fornecidos a componentes que os exigem por meio de parâmetros do construtor.

No arquivo Controllers/MoviesController.cs, o construtor usa Dependency Injection para injetar o contexto de banco de dados MvcMovieContext no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Andaime gerou o seguinte código destacado em Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

O sistema de configuração do ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".

Examinar a string de conexão de base de dados gerada

Scaffolding adicionou uma cadeia de conexão ao arquivo appsettings.json:

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

Para o desenvolvimento local, o sistema de configuração ASP.NET Core lê a chave ConnectionString do arquivo appsettings.json.

A classe InitialCreate

Examine o arquivo de migração Migrations/{timestamp}_InitialCreate.cs:

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

No código anterior:

  • InitialCreate.Up cria a tabela Filme e configura Id como a chave primária.
  • InitialCreate.Down reverte as alterações de esquema feitas pela migração de Up.

Injeção de dependência no controlador

Abra o arquivo Controllers/MoviesController.cs e examine o construtor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

O construtor usa Dependency Injection para injetar o contexto do banco de dados (MvcMovieContext) no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Teste a página Criar. Insira e envie dados.

Teste o Editar, Detalhese Excluir páginas.

Modelos fortemente tipificados e a diretiva @model

No início deste tutorial, você viu como um controlador pode passar dados ou objetos para uma exibição usando o dicionário ViewData. O dicionário ViewData é um objeto dinâmico que fornece uma maneira conveniente e tardia de passar informações para uma exibição.

O MVC fornece a capacidade de passar objetos de modelo fortemente tipados para uma exibição. Essa abordagem fortemente tipada permite a verificação de código em tempo de compilação. O mecanismo de andaime passou por um modelo fortemente tipado na classe MoviesController e visualizações.

Examine o método Details gerado no arquivo Controllers/MoviesController.cs:

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

O parâmetro id geralmente é passado como dados de rota. Por exemplo, o https://localhost:5001/movies/details/1 define:

  • O controlador para o controlador movies, o primeiro segmento de URL.
  • A ação relativa a details, o segundo segmento de URL.
  • O id a 1, o último segmento de URL.

O id pode ser passado com uma cadeia de caracteres de consulta, como no exemplo a seguir:

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

O parâmetro id é definido como um tipo anulável (int?) nos casos em que o valor id não é fornecido.

Um de expressão lambda é passado para o método FirstOrDefaultAsync para selecionar entidades de filme que correspondam aos dados de rota ou ao valor da cadeia de caracteres de consulta.

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

Se um filme for encontrado, uma instância do modelo Movie será passada para a visualização Details:

return View(movie);

Examine o conteúdo do arquivo Views/Movies/Details.cshtml:

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

A instrução @model na parte superior do ficheiro de visualização especifica o tipo de objeto que a vista espera. Quando o controlador de filme foi criado, a seguinte instrução @model foi incluída:

@model MvcMovie.Models.Movie

Esta diretiva @model permite o acesso ao filme que o controlador passou para a vista. O objeto Model é fortemente tipado. Por exemplo, na vista Details.cshtml, o código passa cada campo do filme para os auxiliares HTML DisplayNameFor e DisplayFor com o objeto Model fortemente tipado. Os métodos e exibições Create e Edit também passam por um objeto de modelo Movie.

Verifique a visualização Index.cshtml e o método Index no controlador de Filmes. Observe como o código cria um objeto List quando chama o método View. O código passa essa lista de Movies do método de ação Index para a exibição:

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

O código retorna detalhes do problema caso a propriedade Movie do contexto de dados seja nulo.

Quando o controlador de filmes foi criado, o andaime incluía a seguinte instrução @model na parte superior do arquivo Index.cshtml:

@model IEnumerable<MvcMovie.Models.Movie>

A diretiva @model permite o acesso à lista de filmes que o controlador passou para a visualização usando um objeto Model fortemente digitado. Por exemplo, na visualização Index.cshtml, o código percorre os filmes através de uma instrução foreach aplicada ao objeto fortemente tipado 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>

Como o objeto Model é fortemente tipado como um objeto IEnumerable<Movie>, cada item no loop é tipado como Movie. Entre outros benefícios, o compilador valida os tipos usados no código.

Recursos adicionais

Neste tutorial, as classes são adicionadas para gerenciar filmes em um banco de dados. Estas classes são a parte "Model" da aplicação MVC.

Essas classes de modelo são usadas com Entity Framework Core (EF Core) para trabalhar com um banco de dados. EF Core é uma estrutura de mapeamento objeto-relacional (ORM) que simplifica o código de acesso a dados que você precisa escrever.

As classes de modelo criadas são conhecidas como classes POCO, de Plain Old CLR Objects. As classes POCO não têm qualquer dependência de EF Core. Eles apenas definem as propriedades dos dados a serem armazenados no banco de dados.

Neste tutorial, as classes de modelo são criadas primeiro e EF Core cria o banco de dados.

Adicionar uma classe de modelo de dados

Clique com o botão direito do rato na pasta Modelos>Adicionar>Classe. Nomeie o arquivo Movie.cs.

Atualize o arquivo Models/Movie.cs com o seguinte código:

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

A classe Movie contém um campo Id, que é exigido pelo banco de dados para a chave primária.

O atributo DataType em ReleaseDate especifica o tipo de dados (Date). Com este atributo:

  • O usuário não é obrigado a inserir informações de hora no campo de data.
  • Apenas a data é exibida, não as informações de hora.

DataAnnotations são abordados em um tutorial posterior.

O ponto de interrogação após string indica que a propriedade é anulável. Para obter mais informações, consulte Tipos de referência anuláveis.

Adicionar pacotes NuGet

No menu Ferramentas, selecione Gestor de Pacotes NuGet>Consola do Gestor de Pacotes (PMC).

menu PMC

No PMC, execute o seguinte comando:

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

Os comandos anteriores adicionam:

  • O fornecedor EF Core do SQL Server. O pacote do provedor instala o pacote EF Core como uma dependência.
  • Os utilitários utilizados automaticamente na instalação dos pacotes durante a etapa de estruturação serão abordados mais adiante no tutorial.

Construa o projeto como uma verificação de erros do compilador.

Páginas de filmes em andaimes

Utilize a ferramenta de scaffolding para gerar as páginas Create, Read, Updatee Delete (CRUD) para o modelo de filme.

No Explorador de Soluções, clique com o botão direito na pasta Controladores e selecione Adicionar > Novo Item com Estrutura.

vista da etapa acima

Na caixa de diálogo Adicionar de Andaime, selecione Controlador MVC com modos de exibição, usando o Entity Framework > Adicionar.

caixa de diálogo para adicionar Scaffold

Conclua o Adicionar Controlador MVC com modos de exibição, usando a caixa de diálogo do Entity Framework:

  • No menu pendente da classe Model, selecione Movie (MvcMovie.Models).
  • Na linha classe de contexto Data, selecione o sinal de + (mais).
    • Na caixa de diálogo Adicionar Contexto de Dados, o nome da classe MvcMovie.Data.MvcMovieContext é gerado.
    • Selecione Adicionar.
  • Visualizações e Nome do Controlador: Mantenha o padrão.
  • Selecione Adicionar.

Adicionar contexto de Dados manter os padrões

Se receber uma mensagem de erro, selecione Adicionar uma segunda vez para tentar novamente.

O andaime atualiza o seguinte:

  • Insere as referências de pacote necessárias no arquivo de projeto MvcMovie.csproj.
  • Registra o contexto do banco de dados no arquivo Program.cs.
  • Adiciona uma cadeia de conexão de banco de dados ao arquivo appsettings.json.

O andaime cria o seguinte:

  • Um controlador de filmes: Controllers/MoviesController.cs
  • Razor visualizar arquivos para Criar, Excluir, Detalhes, Editare Índice páginas: Views/Movies/*.cshtml
  • Uma classe de contexto de banco de dados: Data/MvcMovieContext.cs

A criação automática desses arquivos e as atualizações de arquivos são conhecidas como scaffolding.

As páginas com andaimes ainda não podem ser usadas porque o banco de dados não existe. Ao executar a aplicação e selecionar o link Movie App, resulta numa mensagem de erro Não é possível abrir o banco de dados ou não existe tal tabela: Movie.

Crie o aplicativo

Crie o aplicativo. O compilador gera vários avisos sobre como null valores são tratados. Consulte este problema do GitHub e os tipos de referência anuláveis para obter mais informações.

Para eliminar os avisos de tipos de referência anuláveis, remova a seguinte linha do arquivo MvcMovie.csproj:

<Nullable>enable</Nullable>

Esperamos corrigir esse problema na próxima versão.

Migração inicial

Use o recurso EF CoreMigrações para criar o banco de dados. de Migrações é um conjunto de ferramentas que criam e atualizam um banco de dados para corresponder ao modelo de dados.

No menu Ferramentas, selecione Gestor de Pacotes NuGet>Consola do Gestor de Pacotes .

No Console do Gerenciador de Pacotes (PMC), digite os seguintes comandos:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Gera um arquivo de migração Migrations/{timestamp}_InitialCreate.cs. O argumento InitialCreate é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, é selecionado um nome que descreve a migração. Como esta é a primeira migração, a classe gerada contém código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classe MvcMovieContext.

  • Update-Database: Atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Este comando executa o método Up no arquivo Migrations/{time-stamp}_InitialCreate.cs, que cria o banco de dados.

O comando Update-Database gera o seguinte aviso:

Nenhum tipo foi especificado para a coluna decimal 'Preço' no tipo de entidade 'Filme'. Isso fará com que os valores sejam truncados silenciosamente se não se ajustarem à precisão e escala padrão. Especifique explicitamente o tipo de coluna do servidor SQL que pode acomodar todos os valores usando 'HasColumnType()'.

Ignore o aviso anterior, ele é corrigido em um tutorial posterior.

Para obter mais informações sobre as ferramentas PMC para EF Core, consulte a referência das ferramentas EF Core - PMC no Visual Studio.

Testar a aplicação

Execute a aplicação e selecione o link Movie App.

Se tu obtiveres uma exceção semelhante à seguinte, talvez tenhas faltado a etapa de migrações :

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

Observação

Talvez não seja possível inserir vírgulas decimais no campo Price. Para oferecer suporte a de validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e para formatos de data não US-English, o aplicativo deve ser globalizado. Para obter instruções sobre globalização, consulte esta questão do GitHub.

Examine a classe de contexto e o registro do banco de dados gerado

Com EF Core, o acesso aos dados é realizado usando um modelo. Um modelo é composto de classes de entidade e um objeto de contexto que representa uma sessão com o banco de dados. O objeto de contexto permite consultar e salvar dados. O contexto do banco de dados é derivado de Microsoft.EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.

Scaffolding cria a classe de contexto de banco de dados Data/MvcMovieContext.cs:

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

O código anterior cria uma propriedade DbSet<Movie> que representa os filmes no banco de dados.

Injeção de dependência

ASP.NET Core foi criado com injeção de dependência (DI). Serviços, como o contexto do banco de dados, são registrados com DI em Program.cs. Esses serviços são fornecidos a componentes que os exigem por meio de parâmetros do construtor.

No arquivo Controllers/MoviesController.cs, o construtor usa Dependency Injection para injetar o contexto de banco de dados MvcMovieContext no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Scaffolding gerou o seguinte código destacado em Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

O sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".

Examine a cadeia de conexão à base de dados gerada

Scaffolding adicionou uma cadeia de conexão ao arquivo appsettings.json:

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

Para o desenvolvimento local, o sistema de configuração ASP.NET Core lê a chave ConnectionString do arquivo appsettings.json.

A classe InitialCreate

Examine o arquivo de migração Migrations/{timestamp}_InitialCreate.cs:

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

No código anterior:

  • InitialCreate.Up cria a tabela Filme e configura Id como a chave primária.
  • InitialCreate.Down reverte as alterações de esquema feitas pela migração de Up.

Injeção de dependência no controlador

Abra o arquivo Controllers/MoviesController.cs e examine o construtor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

O construtor usa Dependency Injection para injetar o contexto do banco de dados (MvcMovieContext) no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Teste a página Criar. Insira e envie dados.

Teste a página Editar, a página Detalhes, e a página Apagar.

Modelos fortemente tipificados e a diretiva @model

No início deste tutorial, você viu como um controlador pode passar dados ou objetos para uma exibição usando o dicionário ViewData. O dicionário ViewData é um objeto dinâmico que fornece uma maneira conveniente e tardia de passar informações para uma exibição.

O MVC fornece a capacidade de passar objetos de modelo fortemente tipados para uma exibição. Essa abordagem fortemente tipada permite a verificação de código em tempo de compilação. O mecanismo de andaime passou por um modelo fortemente tipado na classe MoviesController e visualizações.

Examine o método Details gerado no arquivo Controllers/MoviesController.cs:

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

O parâmetro id geralmente é passado como dados de rota. Por exemplo, o https://localhost:5001/movies/details/1 define conjuntos:

  • O controlador para o movies controlador, o primeiro segmento de URL.
  • Ação para details, o segundo segmento do URL.
  • id a 1 é o último segmento do URL.

O id pode ser passado com uma cadeia de caracteres de consulta, como no exemplo a seguir:

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

O parâmetro id é definido como um tipo anulável (int?) nos casos em que o valor id não é fornecido.

Um de expressão lambda é passado para o método FirstOrDefaultAsync para selecionar entidades de filme que correspondam aos dados de rota ou ao valor da cadeia de caracteres de consulta.

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

Se um filme for encontrado, uma instância do modelo Movie será passada para a visualização Details:

return View(movie);

Examine o conteúdo do arquivo Views/Movies/Details.cshtml:

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

A instrução @model na parte superior do ficheiro de vista especifica o tipo de objeto que a vista espera. Quando o controlador de filme foi criado, a seguinte instrução @model foi incluída:

@model MvcMovie.Models.Movie

Esta diretiva @model permite o acesso ao filme que o controlador passou para a visualização. O objeto Model é fortemente tipado. Por exemplo, na visualização Details.cshtml, o código passa cada campo do filme para os DisplayNameFor e DisplayFor HTML Helpers com o objeto Model fortemente tipado. Os métodos e exibições Create e Edit também passam por um objeto de modelo Movie.

Examine a visualização Index.cshtml e o método Index no controlador Movies. Observe como o código cria um objeto List quando chama o método View. O código passa essa lista de Movies do método de ação Index para a exibição:

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

Quando o controlador de filmes foi criado, o andaime incluía a seguinte instrução @model na parte superior do arquivo Index.cshtml:

@model IEnumerable<MvcMovie.Models.Movie>

A diretiva @model permite o acesso à lista de filmes que o controlador passou para a visualização usando um objeto Model fortemente digitado. Por exemplo, na visualização Index.cshtml, o código percorre os filmes com uma instrução foreach sobre um objeto fortemente tipado 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>

Como o objeto Model é fortemente tipado como um objeto IEnumerable<Movie>, cada item no loop é tipado como Movie. Entre outros benefícios, o compilador valida os tipos usados no código.

Recursos adicionais

Neste tutorial, as classes são adicionadas para gerenciar filmes em um banco de dados. Estas classes são a parte "Model" da aplicação MVC.

Essas classes de modelo são usadas com Entity Framework Core (EF Core) para trabalhar com um banco de dados. EF Core é uma estrutura de mapeamento objeto-relacional (ORM) que simplifica o código de acesso a dados que você precisa escrever.

As classes de modelo criadas são conhecidas como classes POCO, de Plain Old CLR Objects. As classes POCO não têm qualquer dependência de EF Core. Eles apenas definem as propriedades dos dados a serem armazenados no banco de dados.

Neste tutorial, as classes de modelo são criadas primeiro e EF Core cria o banco de dados.

Adicionar uma classe de modelo de dados

Clique com o botão direito do rato na pasta Modelos>Adicionar>Classe. Nomeie o arquivo Movie.cs.

Atualize o arquivo Models/Movie.cs com o seguinte código:

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

A classe Movie contém um campo Id, que é exigido pelo banco de dados para a chave primária.

O atributo DataType em ReleaseDate especifica o tipo de dados (Date). Com este atributo:

  • O usuário não é obrigado a inserir informações de hora no campo de data.
  • Apenas a data é exibida, não as informações de hora.

DataAnnotations são abordados em um tutorial posterior.

Adicionar pacotes NuGet

No menu Ferramentas, selecione Gestor de Pacotes NuGet>Consola do Gestor de Pacotes (PMC).

menu PMC

No PMC, execute o seguinte comando:

Install-Package Microsoft.EntityFrameworkCore.Design

Os comandos anteriores adicionam:

  • O provedor do SQL Server EF Core. O pacote do provedor instala o pacote EF Core como uma dependência.
  • Os utilitários utilizados pelos pacotes instalados automaticamente na etapa de estruturação, serão abordados mais adiante no tutorial.

Construa o projeto como uma verificação de erros do compilador.

Páginas de filmes em andaimes

Use a ferramenta de andaime para produzir as páginas Create, Read, Updatee Delete (CRUD) para o modelo do filme.

No Explorador de Soluções , clique com o botão direito do rato na pasta Controladores e selecione Adicionar > Novo Item Estruturado.

vista da etapa acima

Na caixa de diálogo Adicionar Scaffold, selecione Controlador MVC com vistas, utilizando o Entity Framework > Adicionar.

Adicionar estrutura

Conclua o Adicionar Controlador MVC com modos de exibição, usando a caixa de diálogo do Entity Framework:

  • Na lista suspensa classe Model, selecione Filme (MvcMovie.Models).
  • Na linha da classe de contexto Data, selecione o + (mais).
    • Na caixa de diálogo Adicionar Contexto de Dados , é gerado o nome da classe MvcMovie.Data.MvcMovieContext .
    • Selecione Adicionar.
  • Visualizações e nome do controlador: Mantenha o padrão.
  • Selecione Adicionar.

Adicionar contexto de dados manter as configurações padrão

O andaime atualiza o seguinte:

  • Insere as referências de pacote necessárias no arquivo de projeto MvcMovie.csproj.
  • Regista o contexto da base de dados em Startup.ConfigureServices do ficheiro Startup.cs.
  • Adiciona uma cadeia de conexão de banco de dados ao arquivo appsettings.json.

O andaime cria o seguinte:

  • Um controlador de filmes: Controllers/MoviesController.cs
  • Razor visualizar ficheiros para Criar, Apagar, Detalhes, Editare Índice páginas: Views/Movies/*.cshtml
  • Uma classe de contexto de banco de dados: Data/MvcMovieContext.cs

A criação automática desses arquivos e atualizações de arquivos é conhecida como scaffolding.

As páginas com andaimes ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link do Movie App resulta numa mensagem de erro Não é possível abrir o banco de dados ou nenhuma tabela chamada Movie.

Migração inicial

Use a funcionalidade EF CoreMigrações para criar a base de dados. As migrações são um conjunto de ferramentas que criam e atualizam um banco de dados para corresponder ao modelo de dados.

No menu Ferramentas, selecione Gestor de Pacotes NuGet>Console do Gestor de Pacotes.

No Console do Gerenciador de Pacotes (PMC), digite os seguintes comandos:

Add-Migration InitialCreate
Update-Database

  • Add-Migration InitialCreate: Gera um arquivo de migração Migrations/{timestamp}_InitialCreate.cs. O argumento InitialCreate é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, é selecionado um nome que descreve a migração. Como esta é a primeira migração, a classe gerada contém código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classe MvcMovieContext.

  • Update-Database: Atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Este comando executa o método Up no arquivo Migrations/{time-stamp}_InitialCreate.cs, que cria o banco de dados.

O comando Update-Database gera o seguinte aviso:

Nenhum tipo foi especificado para a coluna decimal 'Preço' no tipo de entidade 'Filme'. Isso fará com que os valores sejam truncados silenciosamente se não se ajustarem à precisão e escala padrão. Especifique explicitamente o tipo de coluna do servidor SQL que pode acomodar todos os valores usando 'HasColumnType()'.

Ignore o aviso anterior, ele é corrigido em um tutorial posterior.

Para mais informações sobre as ferramentas PMC para EF Core, consulte a referência de ferramentas EF Core - PMC no Visual Studio.

Testar a aplicação

Execute a aplicação e selecione o link Movie App.

Se obtiveres uma exceção semelhante à seguinte, é possível que tenhas falhado o passo das migrações :

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

Observação

Talvez não seja possível inserir vírgulas decimais no campo Price. Para oferecer suporte à validação do jQuery para em locais não ingleses que usam uma vírgula (",") como ponto decimal e para formatos de data que não sejam US-English, o aplicativo deve ser globalizado. Para obter instruções sobre globalização, consulte esta questão do GitHub .

Examine a classe de contexto e o registro do banco de dados gerado

Com EF Core, o acesso aos dados é realizado usando um modelo. Um modelo é composto de classes de entidade e um objeto de contexto que representa uma sessão com o banco de dados. O objeto de contexto permite consultar e salvar dados. O contexto do banco de dados é derivado de Microsoft.EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.

Scaffolding cria a classe de contexto de banco de dados Data/MvcMovieContext.cs:

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

O código anterior cria uma propriedade DbSet<Movie> que representa os filmes no banco de dados.

ASP.NET Core foi desenvolvido com injeção de dependência (DI). Serviços, como o contexto do banco de dados, devem ser registrados com DI em Startup. Os componentes que requerem esses serviços são fornecidos por meio de parâmetros do construtor.

No arquivo Controllers/MoviesController.cs, o construtor usa Dependency Injection para injetar o contexto de banco de dados MvcMovieContext no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Andaime gerou o seguinte código destacado em Startup.ConfigureServices:

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

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

O do sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".

Examinar a cadeia de conexão de banco de dados gerada

Scaffolding adicionou uma cadeia de conexão ao arquivo 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"
  }
}

Para o desenvolvimento local, o sistema de configuração ASP.NET Core lê a chave ConnectionString do arquivo appsettings.json.

A classe InitialCreate

Examine o arquivo de migração Migrations/{timestamp}_InitialCreate.cs:

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

No código anterior:

  • InitialCreate.Up cria a tabela Filme e configura Id como a chave primária.
  • InitialCreate.Down reverte as alterações de esquema feitas pela migração de Up.

Injeção de dependência no controlador

Abra o ficheiro Controllers/MoviesController.cs e examine o construtor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

O construtor usa Dependency Injection para injetar o contexto do banco de dados (MvcMovieContext) no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Teste a página Criar. Insira e envie dados.

Teste as páginas Editar, Detalhese Eliminar.

Modelos fortemente tipados e a diretiva @model

No início deste tutorial, você viu como um controlador pode passar dados ou objetos para uma exibição usando o dicionário ViewData. O dicionário ViewData é um objeto dinâmico que fornece uma maneira conveniente e tardia de passar informações para uma exibição.

O MVC fornece a capacidade de passar objetos de modelo fortemente tipados para uma exibição. Esta abordagem de tipagem forte permite a verificação de código em tempo de compilação. O mecanismo de andaime passou por um modelo fortemente tipado na classe MoviesController e visualizações.

Examine o método Details gerado no arquivo Controllers/MoviesController.cs:

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

O parâmetro id geralmente é passado como dados de rota. Por exemplo, https://localhost:5001/movies/details/1 define:

  • O controlador para movies, o primeiro segmento de URL.
  • A ação para details, o segundo segmento de URL.
  • O id até 1, o último segmento do URL.

O id pode ser passado com uma cadeia de caracteres de consulta, como no exemplo a seguir:

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

O parâmetro id é definido como um tipo anulável (int?) nos casos em que o valor id não é fornecido.

Um de expressão lambda é passado para o método FirstOrDefaultAsync para selecionar entidades de filme que correspondam aos dados de rota ou ao valor da cadeia de caracteres de consulta.

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

Se um filme for encontrado, uma instância do modelo Movie será passada para a visualização Details:

return View(movie);

Examine o conteúdo do arquivo Views/Movies/Details.cshtml:

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

A instrução @model na parte superior do ficheiro de vista especifica o tipo de objeto que a vista espera. Quando o controlador de filme foi criado, a seguinte instrução @model foi incluída:

@model MvcMovie.Models.Movie

Esta diretiva @model permite o acesso ao filme que o controlador passou para a vista. O objeto Model é fortemente tipado. Por exemplo, na visualização Details.cshtml, o código passa cada campo de filme para os auxiliares HTML DisplayNameFor e DisplayFor com o objeto de tipagem forte Model. Os métodos e exibições Create e Edit também passam por um objeto de modelo Movie.

Examine a visualização Index.cshtml e o método Index no controlador Movies. Observe como o código cria um objeto List quando chama o método View. O código passa esta lista Movies do método de ação Index para a vista:

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

Quando o controlador de filmes foi criado, o scaffolding incluiu a seguinte instrução @model no topo do arquivo Index.cshtml:

@model IEnumerable<MvcMovie.Models.Movie>

A diretiva @model permite o acesso à lista de filmes que o controlador passou para a visualização usando um objeto Model fortemente digitado. Por exemplo, na visualização Index.cshtml, o código percorre os filmes com uma instrução foreach sobre o objeto Model fortemente tipado:

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

Como o objeto Model é fortemente tipado como um objeto IEnumerable<Movie>, cada item no loop é do tipo Movie. Entre outros benefícios, o compilador valida os tipos usados no código.

Registo de SQL do Entity Framework Core

A configuração de registro em log geralmente é fornecida pela seção Logging de arquivos appsettings.{Environment}.json. Para registrar instruções SQL, adicione "Microsoft.EntityFrameworkCore.Database.Command": "Information" ao arquivo 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": "*"
}

Com o JSON anterior, as instruções SQL são exibidas na linha de comando e na janela de saída do Visual Studio.

Para obter mais informações, consulte Logging in .NET Core e ASP.NET Core e este problema do GitHub.

Recursos adicionais

Neste tutorial, as classes são adicionadas para gerenciar filmes em um banco de dados. Estas classes são a parte "Model" da aplicação MVC.

Essas classes de modelo são usadas com Entity Framework Core (EF Core) para trabalhar com um banco de dados. EF Core é uma estrutura de mapeamento objeto-relacional (ORM) que simplifica o código de acesso a dados que você precisa escrever.

As classes de modelo criadas são conhecidas como POCO classes, derivadas de Plain Old CLR Objects. As classes POCO não têm qualquer dependência de EF Core. Eles apenas definem as propriedades dos dados a serem armazenados no banco de dados.

Neste tutorial, as classes de modelo são criadas primeiro e EF Core cria o banco de dados.

Adicionar uma classe de modelo de dados

Clique com o botão direito do rato na pasta Modelos>Adicionar>Classe. Nomeie o arquivo Movie.cs.

Atualize o arquivo Movie.cs com o seguinte código:

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

A classe Movie contém um campo Id, que é exigido pelo banco de dados para a chave primária.

O atributo DataType em ReleaseDate especifica o tipo de dados (Date). Com este atributo:

  • O usuário não é obrigado a inserir informações de hora no campo de data.
  • Apenas a data é exibida, não as informações de hora.

DataAnnotations são abordados em um tutorial posterior.

Adicionar pacotes NuGet

No menu Ferramentas, selecione Gestor de Pacotes NuGet>Consola do Gestor de Pacotes (PMC).

menu PMC

No PMC, execute o seguinte comando:

Install-Package Microsoft.EntityFrameworkCore.SqlServer

O comando anterior adiciona o provedor EF Core SQL Server. O pacote do provedor instala o pacote EF Core como uma dependência. Pacotes adicionais são instalados automaticamente na etapa de andaimes mais adiante no tutorial.

Criar uma classe de contexto de banco de dados

É necessária uma classe de contexto de base de dados para coordenar a funcionalidade de EF Core (Criar, Ler, Atualizar, Excluir) para o modelo Movie. O contexto do banco de dados é derivado de Microsoft.EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.

Crie uma pasta Data.

Adicione um arquivo Data/MvcMovieContext.cs com o seguinte código:

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

O código anterior cria uma propriedade DbSet<Movie> para o conjunto de entidades. Na terminologia do Entity Framework, um conjunto de entidades normalmente corresponde a uma tabela de banco de dados. Uma entidade corresponde a uma linha na tabela.

Registrar o contexto do banco de dados

ASP.NET Core é construído com injeção de dependência (DI). Os serviços (como o contexto de banco de dados EF Core) devem ser registrados com DI durante a inicialização do aplicativo. Os componentes que requerem esses serviços (como Razor Pages) são fornecidos por meio de parâmetros do construtor. O código do construtor que obtém uma instância de contexto de banco de dados é mostrado posteriormente no tutorial. Nesta seção, você registra o contexto do banco de dados com o contêiner DI.

Adicione as seguintes instruções using na parte superior do Startup.cs:

using MvcMovie.Data;
using Microsoft.EntityFrameworkCore;

Adicione o seguinte código realçado em Startup.ConfigureServices:

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

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

O nome da cadeia de conexão é passado para o contexto chamando um método em um objeto DbContextOptions. Para o desenvolvimento local, o sistema de configuração ASP.NET Core lê a cadeia de conexão do arquivo appsettings.json.

Examinar a cadeia de conexão do banco de dados

Adicione uma cadeia de conexão ao arquivo 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"
  }
}

Construa o projeto como uma verificação de erros do compilador.

Páginas de filmes em andaimes

Use a ferramenta de andaime para produzir páginas CRUD (Criar, Ler, Atualizar e Excluir) para o modelo de filme.

No Gerenciador de Soluções , clique com o botão direito do mouse na pasta Controladores> Adicionar > Novo Item Andaime.

vista da etapa acima

Na caixa de diálogo Adicionar Scaffold, selecione Controlador MVC com vistas, usando o Entity Framework > Adicionar.

Adicionar Caixa de Diálogo Scaffold

Preencha a caixa de diálogo Adicionar controlador:

  • Classe de modelo:Movie (MvcMovie.Models)
  • Classe de contexto de dados:MvcMovieContext (MvcMovie.Data)

Adicionar dados de contexto

  • Visualizações: Manter o padrão de cada opção marcado
  • Nome do controlador: Manter o padrão MoviesController
  • Selecione Adicionar

O Visual Studio cria:

  • Um controlador de filmes (Controllers/MoviesController.cs)
  • Razor visualizar arquivos para as páginas Criar, Excluir, Detalhes, Editar e Índice (*Visualizações/Filmes/'.cshtml')

A criação automática desses arquivos é conhecida como scaffolding.

Ainda não é possível usar as páginas com andaimes porque o banco de dados não existe. Se você executar o aplicativo e clicar no link do Movie App, receberá uma mensagem de erro Não é possível abrir o banco de dados ou não nenhuma tabela: Movie.

Migração inicial

Use o recurso EF CoreMigrações para criar o banco de dados. Migrações é um conjunto de ferramentas que permite criar e atualizar um banco de dados para corresponder ao seu modelo de dados.

No menu Ferramentas, selecione Gestor de Pacotes NuGet>Consola do Gestor de Pacotes (PMC).

No PMC, digite os seguintes comandos:

Add-Migration InitialCreate
Update-Database
  • Add-Migration InitialCreate: Gera um arquivo de migração Migrations/{timestamp}_InitialCreate.cs. O argumento InitialCreate é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, é selecionado um nome que descreve a migração. Como esta é a primeira migração, a classe gerada contém código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classe MvcMovieContext.

  • Update-Database: Atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Este comando executa o método Up no arquivo Migrations/{time-stamp}_InitialCreate.cs, que cria o banco de dados.

    O comando database update gera o seguinte aviso:

    Nenhum tipo foi especificado para a coluna decimal 'Preço' no tipo de entidade 'Filme'. Isso fará com que os valores sejam truncados silenciosamente se não se ajustarem à precisão e escala padrão. Especifique explicitamente o tipo de coluna do servidor SQL que pode acomodar todos os valores usando 'HasColumnType()'.

    Você pode ignorar esse aviso, ele será corrigido em um tutorial posterior.

Para obter mais informações sobre as ferramentas PMC para EF Core, consulte a referência de ferramentas EF Core - PMC no Visual Studio.

A classe InitialCreate

Examine o arquivo de migração Migrations/{timestamp}_InitialCreate.cs:

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

O método Up cria a tabela Movie e configura Id como a chave primária. O método Down reverte as alterações de esquema feitas pela migração de Up.

Testar a aplicação

  • Execute a aplicação e clique no link Movie App.

    Se você obtiver uma exceção semelhante a uma das seguintes:

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

Você provavelmente perdeu o passo de migrações .

  • Teste a página Criar. Insira e envie dados.

    Observação

    Talvez não seja possível inserir vírgulas decimais no campo Price. Para oferecer suporte a de validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e para formatos de data não US-English, o aplicativo deve ser globalizado. Para obter instruções sobre globalização, consulte esta questão do GitHub.

  • Teste o Editar, Detalhese Excluir páginas.

Injeção de dependência no controlador

Abra o ficheiro Controllers/MoviesController.cs e examine o construtor:

public class MoviesController : Controller
{
    private readonly MvcMovieContext _context;

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

O construtor usa Dependency Injection para injetar o contexto do banco de dados (MvcMovieContext) no controlador. O contexto do banco de dados é usado em cada um dos métodos CRUD no controlador.

Modelos fortemente tipados e a palavra-chave @model

No início deste tutorial, você viu como um controlador pode passar dados ou objetos para uma exibição usando o dicionário ViewData. O dicionário ViewData é um objeto dinâmico que fornece uma maneira conveniente e tardia de passar informações para uma exibição.

O MVC também oferece a capacidade de passar objetos de modelo fortemente tipados para uma exibição. Esta abordagem fortemente tipada permite a verificação de código durante o tempo de compilação. O mecanismo de andaime usou essa abordagem (ou seja, passar um modelo fortemente tipado) com a classe MoviesController e as visualizações.

Examine o método Details gerado no arquivo Controllers/MoviesController.cs:

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

O parâmetro id geralmente é passado como dados de rota. Por exemplo, https://localhost:5001/movies/details/1 define:

  • O controlador para o movies (o primeiro segmento de URL).
  • A ação relacionada a details (o segundo segmento de URL).
  • O id é 1 (o segmento final do URL).

Você também pode passar o id com uma string de consulta da seguinte maneira:

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

O parâmetro id é definido como um tipo anulável (int?) caso um valor de ID não seja fornecido.

Uma expressão lambda é passada para FirstOrDefaultAsync para selecionar entidades de filmes que correspondam aos dados de rota ou ao valor da cadeia de consulta.

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

Se um filme for encontrado, uma instância do modelo Movie será passada para a visualização Details:

return View(movie);

Examine o conteúdo do arquivo Views/Movies/Details.cshtml:

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

A instrução @model na parte superior do ficheiro de vista especifica o tipo de objeto que a vista espera. Quando o controlador de filme foi criado, a seguinte instrução @model foi incluída:

@model MvcMovie.Models.Movie

Esta diretiva @model permite o acesso ao filme que o controlador passou para a vista. O objeto Model é fortemente tipado. Por exemplo, na visualização Details.cshtml, o código passa cada campo de filme para os Helpers HTML DisplayNameFor e DisplayFor com o objeto fortemente tipado Model. Os métodos e exibições Create e Edit também passam por um objeto de modelo Movie.

Examine a visualização Index.cshtml e o método Index no controlador de filmes. Observe como o código cria um objeto List quando chama o método View. O código passa essa lista de Movies do método de ação Index para a exibição:

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

Quando o controlador de filmes foi criado, o scaffolding incluiu a seguinte instrução @model no início do ficheiro Index.cshtml.

@model IEnumerable<MvcMovie.Models.Movie>

A diretiva @model permite que você acesse a lista de filmes que o controlador passou para a exibição usando um objeto Model que é fortemente tipado. Por exemplo, na visualização Index.cshtml, o código percorre os filmes com uma instrução foreach sobre o objeto Model fortemente tipado:

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

Como o objeto Model é fortemente tipado (como um objeto IEnumerable<Movie>), cada item no loop é tipado como Movie. Entre outros benefícios, isso significa que você obtém verificação de tempo de compilação do código.

Recursos adicionais