Parte 4, adicione um modelo a um aplicativo ASP.NET Core MVC
Observação
Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Aviso
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
Importante
Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.
Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.
By Rick Anderson e Jon P Smith.
Neste tutorial, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes serão a parte do “Modelo” parte do aplicativo MVC.
Essas classes do modelo são usadas com o Entity Framework Core (EF Core) para trabalhar com um banco de dados. O EF Core é uma estrutura ORM (mapeamento relacional de objetos) 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 (Bons e velhos objetos do CLR). As classes POCO não têm nenhuma dependência em EF Core. Elas definem as propriedades dos dados a serem armazenados no banco de dados.
Neste tutorial, você escreve as classes de modelo primeiro e o EF Core cria o banco de dados.
Adicionar uma classe de modelo de dados
Clique com o botão direito do mouse na pasta Modelos >Adicionar>Classe. Dê o nome Movie.cs
para o arquivo.
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 esse atributo:
- O usuário não precisa inserir informações de horário no campo de data.
- Somente a data é exibida, não as informações de tempo.
DataAnnotations são abordados em um tutorial posterior.
O ponto de interrogação após string
indica que a propriedade permite valor nulo. Para obter mais informações, confira Tipos de referência anuláveis.
Adicionar pacotes do NuGet
O Visual Studio instala automaticamente os pacotes necessários.
Compile o projeto como uma verificação de erros do compilador.
Aplicar scaffold a páginas de filme
Use a ferramenta scaffolding para produzir páginas CRUD (Create
, Read
, Update
e Delete
) para o modelo de filme.
Clique com o botão direito do mouse na pasta Controladores do Gerenciador de Soluções e selecione Adicionar > Novo Item Gerado por Scaffolding.
No diálogo Adicionar novo item de Scaffold:
- No painel esquerdo, selecione Instalado>Comum>MVC.
- Selecione Controlador MVC com exibições, usando o Entity Framework.
- Selecione Adicionar.
Complete a caixa de diálogo Adicionar Controlador MVC com exibições, usando o Entity Framework:
- Na lista suspensa Classe de modelo, selecione Filme (MvcMovie.Models).
- Na linha Classe de contexto de dados, selecione o sinal + (adição).
- 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.
- Exibições e Nome do controlador: mantenha o padrão.
- Selecione Adicionar.
Se você receber uma mensagem de erro, selecione Adicionar uma segunda vez para tentar novamente.
O scaffolding adiciona os seguintes pacotes:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
Microsoft.VisualStudio.Web.CodeGeneration.Design
O scaffolding cria o seguinte:
- Um controlador de filmes:
Controllers/MoviesController.cs
- Razor exibir arquivos para páginas Criar, Excluir, Detalhes, Editar e Índice :
Views/Movies/*.cshtml
- Uma classe de contexto de banco de dados:
Data/MvcMovieContext.cs
O scaffolding 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
. - Adicionar uma cadeia de caracteres de conexão do 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 scaffolding ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link Aplicativo de Filme resulta em uma mensagem de erro Não é possível abrir o banco de dados ou nenhuma tabela desse tipo: filme.
Crie o aplicativo para verificar se não há erros.
Migração inicial
Use o recurso EF CoreMigrações para criar o banco de dados. O recurso Migrações é um conjunto de ferramentas que cria e atualiza um banco de dados para corresponder ao modelo de dados.
No menu Ferramentas, selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes.
No PMC (Console do Gerenciador de Pacotes), Insira o seguinte comando:
Add-Migration InitialCreate
Add-Migration InitialCreate
: gera um arquivo de migraçãoMigrations/{timestamp}_InitialCreate.cs
. O argumentoInitialCreate
é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, um nome que descreve a migração é selecionado. Como essa é a primeira migração, a classe gerada contém o código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classeMvcMovieContext
.
O seguinte aviso é exibido, que é abordado em uma etapa posterior:
Nenhum tipo de repositório foi especificado para a propriedade decimal 'Price' no tipo de entidade 'Movie'. Isso fará com que valores sejam truncados silenciosamente se não couberem na precisão e na escala padrão. Especifique explicitamente o tipo de coluna do SQL Server que pode acomodar todos os valores em 'OnModelCreating' usando 'HasColumnType', especifique precisão e escala usando 'HasPrecision' ou configure um conversor de valor usando 'HasConversion'.
No PMC, insira o seguinte comando:
Update-Database
Update-Database
: Atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Esse comando executa o métodoUp
no arquivoMigrations/{time-stamp}_InitialCreate.cs
, que cria o banco de dados.
Para obter mais informações sobre as ferramentas PMC para EF Core, veja a referência de ferramentas de EF Core – PMC no Visual Studio.
Testar o aplicativo
Execute o aplicativo e clique no link Aplicativo de Filme.
Se você receber uma exceção semelhante à seguinte, talvez tenha 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 você não consiga inserir casas decimais ou vírgulas no campo Price
. Para dar suporte à validação do jQuery para localidades com idiomas diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data diferentes do inglês dos EUA, o aplicativo precisa ser globalizado. Para obter instruções sobre a globalização, consulte esse problema no GitHub.
Examinar a classe de contexto e o registro do banco de dados gerados
Com o EF Core, o acesso aos dados é executado usando um modelo. Um modelo é feito 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 de banco de dados é derivado de Microsoft. EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
O scaffolding cria a classe de contexto do 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
O ASP.NET Core foi criado com a DI (injeção de dependência). Serviços, como o contexto do banco de dados, são registrados com DI no Program.cs
. Esses serviços são fornecidos aos componentes que necessitam deles através de parâmetros do construtor.
No arquivo Controllers/MoviesController.cs
, o construtor usa a Injeção de Dependência para injetar o contexto do banco de dados MvcMovieContext
no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
O 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") ?? throw new InvalidOperationException("Connection string 'MvcMovieContext' not found.")));
O sistema de configuração ASP.NET Core faz a leitura da cadeia de caracteres de conexão de banco de dados "MvcMovieContext".
Examinar a cadeia de caracteres de conexão de banco de dados gerada
O 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"
}
}
No desenvolvimento local, o sistema de configuração do ASP.NET Core lê a chave ConnectionString
do arquivo appsettings.json
.
A classe InitialCreate
Examinar 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 de Filmes e configuraId
como a chave primária.- O método
InitialCreate.Down
reverte as alterações de esquema feitas pela migração deUp
.
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 a Injeção de Dependência para injetar o contexto de banco de dados (MvcMovieContext
) no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
Teste a página Criar. Inserir e enviar dados.
Teste os links Editar, Detalhes e Excluir.
Modelos fortemente tipados e a diretiva @model
Anteriormente neste 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 de associação tardia para passar informações para uma exibição.
O MVC também 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 scaffolding passou um modelo fortemente tipado na classe e nas exibições de MoviesController
.
Examine o método de 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 controlador
movies
, o primeiro segmento da URL. - A ação para
details
, o segundo segmento da URL. - O
id
para 1, o último segmento da 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 que permite valor nulo (int?
) nos casos em que o valor de id
não seja fornecido.
Um expressão lambda é passada para o método FirstOrDefaultAsync para selecionar as entidades de filmes que correspondem ao valor dos dados da rota ou da cadeia de consulta.
var movie = await _context.Movie
.FirstOrDefaultAsync(m => m.Id == id);
Se for encontrado um filme, uma instância do modelo Movie
será passada para a exibição Details
:
return View(movie);
Examinar 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 exibição especifica o tipo de objeto que a exibição espera. Quando o controlador de filme foi criado, a seguinte instrução @model
foi incluída:
@model MvcMovie.Models.Movie
Essa diretiva @model
permite o acesso ao filme que o controlador passou para a exibição. O objeto Model
é fortemente tipado. Por exemplo, na exibição Details.cshtml
, o código passa cada campo de filme para os Auxiliares de HTML DisplayNameFor
e DisplayFor
com o objeto fortemente tipado Model
. Os métodos Create
e Edit
e as exibições também passam um objeto de modelo Movie
.
Examine a exibição Index.cshtml
e o método Index
no controlador Filmes. Observe como o código cria um objeto List
quando ele chama o método View
. O código passa esta lista 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 retornará os detalhes do problema se a propriedade Movie
do contexto dos dados for nula.
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 acessar a lista de filmes que o controlador passou para a exibição usando um objeto Model
fortemente tipado. Por exemplo, na exibição Index.cshtml
o código executa um loop pelos filmes com uma instrução foreach
no 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, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes serão a parte do “Modelo” parte do aplicativo MVC.
Essas classes do modelo são usadas com o Entity Framework Core (EF Core) para trabalhar com um banco de dados. O EF Core é uma estrutura ORM (mapeamento relacional de objetos) 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 (Bons e velhos objetos do CLR). As classes POCO não têm nenhuma dependência em EF Core. Elas definem as propriedades dos dados a serem armazenados no banco de dados.
Neste tutorial, você escreve as classes de modelo primeiro e o EF Core cria o banco de dados.
Adicionar uma classe de modelo de dados
Clique com o botão direito do mouse na pasta Modelos >Adicionar>Classe. Dê o nome Movie.cs
para o arquivo.
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 esse atributo:
- O usuário não precisa inserir informações de horário no campo de data.
- Somente a data é exibida, não as informações de tempo.
DataAnnotations são abordados em um tutorial posterior.
O ponto de interrogação após string
indica que a propriedade permite valor nulo. Para obter mais informações, confira Tipos de referência anuláveis.
Adicionar pacotes do NuGet
O Visual Studio instala automaticamente os pacotes necessários.
Compile o projeto como uma verificação de erros do compilador.
Aplicar scaffold a páginas de filme
Use a ferramenta scaffolding para produzir páginas CRUD (Create
, Read
, Update
e Delete
) para o modelo de filme.
Clique com o botão direito do mouse na pasta Controladores do Gerenciador de Soluções e selecione Adicionar > Novo Item Gerado por Scaffolding.
No diálogo Adicionar novo item de Scaffold:
- No painel esquerdo, selecione Instalado>Comum>MVC.
- Selecione Controlador MVC com exibições, usando o Entity Framework.
- Selecione Adicionar.
Complete a caixa de diálogo Adicionar Controlador MVC com exibições, usando o Entity Framework:
- Na lista suspensa Classe de modelo, selecione Filme (MvcMovie.Models).
- Na linha Classe de contexto de dados, selecione o sinal + (adição).
- 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.
- Exibições e Nome do controlador: mantenha o padrão.
- Selecione Adicionar.
Se você receber uma mensagem de erro, selecione Adicionar uma segunda vez para tentar novamente.
O scaffolding adiciona os seguintes pacotes:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
Microsoft.VisualStudio.Web.CodeGeneration.Design
O scaffolding cria o seguinte:
- Um controlador de filmes:
Controllers/MoviesController.cs
- Razor exibir arquivos para páginas Criar, Excluir, Detalhes, Editar e Índice :
Views/Movies/*.cshtml
- Uma classe de contexto de banco de dados:
Data/MvcMovieContext.cs
O scaffolding 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
. - Adicionar uma cadeia de caracteres de conexão do 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 scaffolding ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link Aplicativo de Filme resulta em uma mensagem de erro Não é possível abrir o banco de dados ou nenhuma tabela desse tipo: filme.
Crie o aplicativo para verificar se não há erros.
Migração inicial
Use o recurso EF CoreMigrações para criar o banco de dados. O recurso Migrações é um conjunto de ferramentas que cria e atualiza um banco de dados para corresponder ao modelo de dados.
No menu Ferramentas, selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes.
No PMC (Console do Gerenciador de Pacotes), Insira os seguintes comandos:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: gera um arquivo de migraçãoMigrations/{timestamp}_InitialCreate.cs
. O argumentoInitialCreate
é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, um nome que descreve a migração é selecionado. Como essa é a primeira migração, a classe gerada contém o código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classeMvcMovieContext
.Update-Database
: atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Esse comando executa o métodoUp
no arquivoMigrations/{time-stamp}_InitialCreate.cs
, que cria o banco de dados.
O comando Update-Database
gera o seguinte aviso:
Nenhum tipo de repositório foi especificado para a propriedade decimal 'Price' no tipo de entidade 'Movie'. Isso fará com que valores sejam truncados silenciosamente se não couberem na precisão e na escala padrão. Especifique explicitamente o tipo de coluna do SQL Server que pode acomodar todos os valores em 'OnModelCreating' usando 'HasColumnType', especifique precisão e escala usando 'HasPrecision' ou configure um conversor de valor usando 'HasConversion'.
Ignore o aviso anterior, ele é corrigido em um tutorial posterior.
Para obter mais informações sobre as ferramentas PMC para EF Core, veja a referência de ferramentas de EF Core – PMC no Visual Studio.
Testar o aplicativo
Execute o aplicativo e clique no link Aplicativo de Filme.
Se você receber uma exceção semelhante à seguinte, talvez tenha 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 você não consiga inserir casas decimais ou vírgulas no campo Price
. Para dar suporte à validação do jQuery para localidades com idiomas diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data diferentes do inglês dos EUA, o aplicativo precisa ser globalizado. Para obter instruções sobre a globalização, consulte esse problema no GitHub.
Examinar a classe de contexto e o registro do banco de dados gerados
Com o EF Core, o acesso aos dados é executado usando um modelo. Um modelo é feito 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 de banco de dados é derivado de Microsoft. EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
O scaffolding cria a classe de contexto do 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
O ASP.NET Core foi criado com a DI (injeção de dependência). Serviços, como o contexto do banco de dados, são registrados com DI no Program.cs
. Esses serviços são fornecidos aos componentes que necessitam deles através de parâmetros do construtor.
No arquivo Controllers/MoviesController.cs
, o construtor usa a Injeção de Dependência para injetar o contexto do banco de dados MvcMovieContext
no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
O 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 sistema de configuração ASP.NET Core faz a leitura da cadeia de caracteres de conexão de banco de dados "MvcMovieContext".
Examinar a cadeia de caracteres de conexão de banco de dados gerada
O 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"
}
}
No desenvolvimento local, o sistema de configuração do ASP.NET Core lê a chave ConnectionString
do arquivo appsettings.json
.
A classe InitialCreate
Examinar 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 de Filmes e configuraId
como a chave primária.- O método
InitialCreate.Down
reverte as alterações de esquema feitas pela migração deUp
.
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 a Injeção de Dependência para injetar o contexto de banco de dados (MvcMovieContext
) no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
Teste a página Criar. Inserir e enviar dados.
Teste os links Editar, Detalhes e Excluir.
Modelos fortemente tipados e a diretiva @model
Anteriormente neste 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 de associação tardia para passar informações para uma exibição.
O MVC também 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 scaffolding passou um modelo fortemente tipado na classe e nas exibições de MoviesController
.
Examine o método de 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 controlador
movies
, o primeiro segmento da URL. - A ação para
details
, o segundo segmento da URL. - O
id
para 1, o último segmento da 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 que permite valor nulo (int?
) nos casos em que o valor de id
não seja fornecido.
Um expressão lambda é passada para o método FirstOrDefaultAsync para selecionar as entidades de filmes que correspondem ao valor dos dados da rota ou da cadeia de consulta.
var movie = await _context.Movie
.FirstOrDefaultAsync(m => m.Id == id);
Se for encontrado um filme, uma instância do modelo Movie
será passada para a exibição Details
:
return View(movie);
Examinar 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 exibição especifica o tipo de objeto que a exibição espera. Quando o controlador de filme foi criado, a seguinte instrução @model
foi incluída:
@model MvcMovie.Models.Movie
Essa diretiva @model
permite o acesso ao filme que o controlador passou para a exibição. O objeto Model
é fortemente tipado. Por exemplo, na exibição Details.cshtml
, o código passa cada campo de filme para os Auxiliares de HTML DisplayNameFor
e DisplayFor
com o objeto fortemente tipado Model
. Os métodos Create
e Edit
e as exibições também passam um objeto de modelo Movie
.
Examine a exibição Index.cshtml
e o método Index
no controlador Filmes. Observe como o código cria um objeto List
quando ele chama o método View
. O código passa esta lista 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 retornará os detalhes do problema se a propriedade Movie
do contexto dos dados for nula.
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 acessar a lista de filmes que o controlador passou para a exibição usando um objeto Model
fortemente tipado. Por exemplo, na exibição Index.cshtml
o código executa um loop pelos filmes com uma instrução foreach
no 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, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes serão a parte do “Modelo” parte do aplicativo MVC.
Essas classes do modelo são usadas com o Entity Framework Core (EF Core) para trabalhar com um banco de dados. O EF Core é uma estrutura ORM (mapeamento relacional de objetos) 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 (Bons e velhos objetos do CLR). As classes POCO não têm nenhuma dependência em EF Core. Elas definem as propriedades dos dados a serem armazenados no banco de dados.
Neste tutorial, você escreve as classes de modelo primeiro e o EF Core cria o banco de dados.
Adicionar uma classe de modelo de dados
Clique com o botão direito do mouse na pasta Modelos >Adicionar>Classe. Dê o nome Movie.cs
para o arquivo.
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 esse atributo:
- O usuário não precisa inserir informações de horário no campo de data.
- Somente a data é exibida, não as informações de tempo.
DataAnnotations são abordados em um tutorial posterior.
O ponto de interrogação após string
indica que a propriedade permite valor nulo. Para obter mais informações, confira Tipos de referência anuláveis.
Adicionar pacotes do NuGet
O Visual Studio instala automaticamente os pacotes necessários.
Compile o projeto como uma verificação de erros do compilador.
Aplicar scaffold a páginas de filme
Use a ferramenta scaffolding para produzir páginas CRUD (Create
, Read
, Update
e Delete
) para o modelo de filme.
Clique com o botão direito do mouse na pasta Controladores do Gerenciador de Soluções e selecione Adicionar > Novo Item Gerado por Scaffolding.
No diálogo Adicionar novo item de Scaffold:
- No painel esquerdo, selecione Instalado>Comum>MVC.
- Selecione Controlador MVC com exibições, usando o Entity Framework.
- Selecione Adicionar.
Complete a caixa de diálogo Adicionar Controlador MVC com exibições, usando o Entity Framework:
- Na lista suspensa Classe de modelo, selecione Filme (MvcMovie.Models).
- Na linha Classe de contexto de dados, selecione o sinal + (adição).
- 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.
- Exibições e Nome do controlador: mantenha o padrão.
- Selecione Adicionar.
Se você receber uma mensagem de erro, selecione Adicionar uma segunda vez para tentar novamente.
O scaffolding adiciona os seguintes pacotes:
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
Microsoft.VisualStudio.Web.CodeGeneration.Design
O scaffolding cria o seguinte:
- Um controlador de filmes:
Controllers/MoviesController.cs
- Razor exibir arquivos para páginas Criar, Excluir, Detalhes, Editar e Índice :
Views/Movies/*.cshtml
- Uma classe de contexto de banco de dados:
Data/MvcMovieContext.cs
O scaffolding 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
. - Adicionar uma cadeia de caracteres de conexão do 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 scaffolding ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link Aplicativo de Filme resulta em uma mensagem de erro Não é possível abrir o banco de dados ou nenhuma tabela desse tipo: filme.
Crie o aplicativo para verificar se não há erros.
Migração inicial
Use o recurso EF CoreMigrações para criar o banco de dados. O recurso Migrações é um conjunto de ferramentas que cria e atualiza um banco de dados para corresponder ao modelo de dados.
No menu Ferramentas, selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes.
No PMC (Console do Gerenciador de Pacotes), Insira os seguintes comandos:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: gera um arquivo de migraçãoMigrations/{timestamp}_InitialCreate.cs
. O argumentoInitialCreate
é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, um nome que descreve a migração é selecionado. Como essa é a primeira migração, a classe gerada contém o código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classeMvcMovieContext
.Update-Database
: atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Esse comando executa o métodoUp
no arquivoMigrations/{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 valores sejam truncados silenciosamente se não couberem na precisão e na escala padrão. Especifique explicitamente o tipo de coluna do SQL Server 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, veja a referência de ferramentas de EF Core – PMC no Visual Studio.
Testar o aplicativo
Execute o aplicativo e clique no link Aplicativo de Filme.
Se você receber uma exceção semelhante à seguinte, talvez tenha 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 você não consiga inserir casas decimais ou vírgulas no campo Price
. Para dar suporte à validação do jQuery para localidades com idiomas diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data diferentes do inglês dos EUA, o aplicativo precisa ser globalizado. Para obter instruções sobre a globalização, consulte esse problema no GitHub.
Examinar a classe de contexto e o registro do banco de dados gerados
Com o EF Core, o acesso aos dados é executado usando um modelo. Um modelo é feito 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 de banco de dados é derivado de Microsoft. EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
O scaffolding cria a classe de contexto do 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
O ASP.NET Core foi criado com a DI (injeção de dependência). Serviços, como o contexto do banco de dados, são registrados com DI no Program.cs
. Esses serviços são fornecidos aos componentes que necessitam deles através de parâmetros do construtor.
No arquivo Controllers/MoviesController.cs
, o construtor usa a Injeção de Dependência para injetar o contexto do banco de dados MvcMovieContext
no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
O 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 sistema de configuração ASP.NET Core faz a leitura da cadeia de caracteres de conexão de banco de dados "MvcMovieContext".
Examinar a cadeia de caracteres de conexão de banco de dados gerada
O 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"
}
}
No desenvolvimento local, o sistema de configuração do ASP.NET Core lê a chave ConnectionString
do arquivo appsettings.json
.
A classe InitialCreate
Examinar 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 de Filmes e configuraId
como a chave primária.- O método
InitialCreate.Down
reverte as alterações de esquema feitas pela migração deUp
.
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 a Injeção de Dependência para injetar o contexto de banco de dados (MvcMovieContext
) no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
Teste a página Criar. Inserir e enviar dados.
Teste os links Editar, Detalhes e Excluir.
Modelos fortemente tipados e a diretiva @model
Anteriormente neste 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 de associação tardia para passar informações para uma exibição.
O MVC também 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 scaffolding passou um modelo fortemente tipado na classe e nas exibições de MoviesController
.
Examine o método de 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 controlador
movies
, o primeiro segmento da URL. - A ação para
details
, o segundo segmento da URL. - O
id
para 1, o último segmento da 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 que permite valor nulo (int?
) nos casos em que o valor de id
não seja fornecido.
Um expressão lambda é passada para o método FirstOrDefaultAsync para selecionar as entidades de filmes que correspondem ao valor dos dados da rota ou da cadeia de consulta.
var movie = await _context.Movie
.FirstOrDefaultAsync(m => m.Id == id);
Se for encontrado um filme, uma instância do modelo Movie
será passada para a exibição Details
:
return View(movie);
Examinar 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 exibição especifica o tipo de objeto que a exibição espera. Quando o controlador de filme foi criado, a seguinte instrução @model
foi incluída:
@model MvcMovie.Models.Movie
Essa diretiva @model
permite o acesso ao filme que o controlador passou para a exibição. O objeto Model
é fortemente tipado. Por exemplo, na exibição Details.cshtml
, o código passa cada campo de filme para os Auxiliares de HTML DisplayNameFor
e DisplayFor
com o objeto fortemente tipado Model
. Os métodos Create
e Edit
e as exibições também passam um objeto de modelo Movie
.
Examine a exibição Index.cshtml
e o método Index
no controlador Filmes. Observe como o código cria um objeto List
quando ele chama o método View
. O código passa esta lista 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 retornará os detalhes do problema se a propriedade Movie
do contexto dos dados for nula.
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 acessar a lista de filmes que o controlador passou para a exibição usando um objeto Model
fortemente tipado. Por exemplo, na exibição Index.cshtml
o código executa um loop pelos filmes com uma instrução foreach
no 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, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes serão a parte do “Modelo” parte do aplicativo MVC.
Essas classes do modelo são usadas com o Entity Framework Core (EF Core) para trabalhar com um banco de dados. O EF Core é uma estrutura ORM (mapeamento relacional de objetos) 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 (Bons e velhos objetos do CLR). As classes POCO não têm nenhuma dependência em EF Core. Elas definem as propriedades dos dados a serem armazenados no banco de dados.
Neste tutorial, você escreve as classes de modelo primeiro e o EF Core cria o banco de dados.
Adicionar uma classe de modelo de dados
Clique com o botão direito do mouse na pasta Modelos >Adicionar>Classe. Dê o nome Movie.cs
para o arquivo.
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 esse atributo:
- O usuário não precisa inserir informações de horário no campo de data.
- Somente a data é exibida, não as informações de tempo.
DataAnnotations são abordados em um tutorial posterior.
O ponto de interrogação após string
indica que a propriedade permite valor nulo. Para obter mais informações, confira Tipos de referência anuláveis.
Adicionar pacotes do NuGet
No menu Ferramentas, selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes (PMC).
No PMC, execute o seguinte comando:
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Os comandos anteriores adicionam:
- O provedor EF Core do SQL Server. O pacote do provedor instala o pacote do EF Core como uma dependência.
- Os utilitários usados pelos pacotes instalados automaticamente na etapa de scaffolding, mais adiante no tutorial.
Compile o projeto como uma verificação de erros do compilador.
Aplicar scaffold a páginas de filme
Use a ferramenta scaffolding para produzir páginas CRUD (Create
, Read
, Update
e Delete
) para o modelo de filme.
Clique com o botão direito do mouse na pasta Controladores do Gerenciador de Soluções e selecione Adicionar > Novo Item Gerado por Scaffolding.
Na caixa de diálogo Adicionar Scaffold, selecione Controlador MVC com exibições, usando o Entity Framework > Adicionar.
Complete a caixa de diálogo Adicionar Controlador MVC com exibições, usando o Entity Framework:
- Na lista suspensa Classe de modelo, selecione Filme (MvcMovie.Models).
- Na linha Classe de contexto de dados, selecione o sinal + (adição).
- Na caixa de diálogo Adicionar Contexto de Dados , o nome da classe MvcMovie.Data.MvcMovieContext é gerado.
- Selecione Adicionar.
- Exibições e Nome do controlador: mantenha o padrão.
- Selecione Adicionar.
Se você receber uma mensagem de erro, selecione Adicionar uma segunda vez para tentar novamente.
O scaffolding 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 caracteres de conexão do banco de dados ao arquivo
appsettings.json
.
O scaffolding cria o seguinte:
- Um controlador de filmes:
Controllers/MoviesController.cs
- Razor exibir arquivos para páginas Criar, Excluir, Detalhes, Editar e Índice :
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 scaffolding ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link Aplicativo de Filme resulta em uma mensagem de erro Não é possível abrir o banco de dados ou nenhuma tabela desse tipo: filme.
Criar o aplicativo
Crie o aplicativo. O compilador gera vários avisos sobre como os valores de null
são tratados. Consulte este tópico do GitHub e tipos de referência anuláveis para obter mais informações.
Para eliminar os avisos dos tipos de referência anuláveis, remova a seguinte linha do arquivo MvcMovie.csproj
:
<Nullable>enable</Nullable>
Esperamos ter corrigido esse problema na próxima versão.
Migração inicial
Use o recurso EF CoreMigrações para criar o banco de dados. O recurso Migrações é um conjunto de ferramentas que cria e atualiza um banco de dados para corresponder ao modelo de dados.
No menu Ferramentas, selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes.
No PMC (Console do Gerenciador de Pacotes), Insira os seguintes comandos:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: gera um arquivo de migraçãoMigrations/{timestamp}_InitialCreate.cs
. O argumentoInitialCreate
é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, um nome que descreve a migração é selecionado. Como essa é a primeira migração, a classe gerada contém o código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classeMvcMovieContext
.Update-Database
: atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Esse comando executa o métodoUp
no arquivoMigrations/{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 valores sejam truncados silenciosamente se não couberem na precisão e na escala padrão. Especifique explicitamente o tipo de coluna do SQL Server 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, veja a referência de ferramentas de EF Core – PMC no Visual Studio.
Testar o aplicativo
Execute o aplicativo e clique no link Aplicativo de Filme.
Se você receber uma exceção semelhante à seguinte, talvez tenha perdido a etapa de migrações:
SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.
Observação
Talvez você não consiga inserir casas decimais ou vírgulas no campo Price
. Para dar suporte à validação do jQuery para localidades com idiomas diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data diferentes do inglês dos EUA, o aplicativo precisa ser globalizado. Para obter instruções sobre a globalização, consulte esse problema no GitHub.
Examinar a classe de contexto e o registro do banco de dados gerados
Com o EF Core, o acesso aos dados é executado usando um modelo. Um modelo é feito 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 de banco de dados é derivado de Microsoft. EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
O scaffolding cria a classe de contexto do 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
O ASP.NET Core foi criado com a DI (injeção de dependência). Serviços, como o contexto do banco de dados, são registrados com DI no Program.cs
. Esses serviços são fornecidos aos componentes que necessitam deles através de parâmetros do construtor.
No arquivo Controllers/MoviesController.cs
, o construtor usa a Injeção de Dependência para injetar o contexto do banco de dados MvcMovieContext
no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
O 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 sistema de configuração ASP.NET Core faz a leitura da cadeia de caracteres de conexão de banco de dados "MvcMovieContext".
Examinar a cadeia de caracteres de conexão de banco de dados gerada
O 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"
}
}
No desenvolvimento local, o sistema de configuração do ASP.NET Core lê a chave ConnectionString
do arquivo appsettings.json
.
A classe InitialCreate
Examinar 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 de Filmes e configuraId
como a chave primária.- O método
InitialCreate.Down
reverte as alterações de esquema feitas pela migração deUp
.
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 a Injeção de Dependência para injetar o contexto de banco de dados (MvcMovieContext
) no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
Teste a página Criar. Inserir e enviar dados.
Teste os links Editar, Detalhes e Excluir.
Modelos fortemente tipados e a diretiva @model
Anteriormente neste 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 de associação tardia para passar informações para uma exibição.
O MVC também 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 scaffolding passou um modelo fortemente tipado na classe e nas exibições de MoviesController
.
Examine o método de 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 controlador
movies
, o primeiro segmento da URL. - A ação para
details
, o segundo segmento da URL. - O
id
para 1, o último segmento da 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 que permite valor nulo (int?
) nos casos em que o valor de id
não seja fornecido.
Um expressão lambda é passada para o método FirstOrDefaultAsync para selecionar as entidades de filmes que correspondem ao valor dos dados da rota ou da cadeia de consulta.
var movie = await _context.Movie
.FirstOrDefaultAsync(m => m.Id == id);
Se for encontrado um filme, uma instância do modelo Movie
será passada para a exibição Details
:
return View(movie);
Examinar 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 exibição especifica o tipo de objeto que a exibição espera. Quando o controlador de filme foi criado, a seguinte instrução @model
foi incluída:
@model MvcMovie.Models.Movie
Essa diretiva @model
permite o acesso ao filme que o controlador passou para a exibição. O objeto Model
é fortemente tipado. Por exemplo, na exibição Details.cshtml
, o código passa cada campo de filme para os Auxiliares de HTML DisplayNameFor
e DisplayFor
com o objeto fortemente tipado Model
. Os métodos Create
e Edit
e as exibições também passam um objeto de modelo Movie
.
Examine a exibição Index.cshtml
e o método Index
no controlador Filmes. Observe como o código cria um objeto List
quando ele chama o método View
. O código passa esta lista 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
na parte superior do arquivo Index.cshtml
:
@model IEnumerable<MvcMovie.Models.Movie>
A diretiva @model
permite acessar a lista de filmes que o controlador passou para a exibição usando um objeto Model
fortemente tipado. Por exemplo, na exibição Index.cshtml
o código executa um loop pelos filmes com uma instrução foreach
no 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, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes serão a parte do “Modelo” parte do aplicativo MVC.
Essas classes do modelo são usadas com o Entity Framework Core (EF Core) para trabalhar com um banco de dados. O EF Core é uma estrutura ORM (mapeamento relacional de objetos) 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 (Bons e velhos objetos do CLR). As classes POCO não têm nenhuma dependência em EF Core. Elas definem as propriedades dos dados a serem armazenados no banco de dados.
Neste tutorial, você escreve as classes de modelo primeiro e o EF Core cria o banco de dados.
Adicionar uma classe de modelo de dados
Clique com o botão direito do mouse na pasta Modelos >Adicionar>Classe. Dê o nome Movie.cs
para o arquivo.
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 esse atributo:
- O usuário não precisa inserir informações de horário no campo de data.
- Somente a data é exibida, não as informações de tempo.
DataAnnotations são abordados em um tutorial posterior.
Adicionar pacotes do NuGet
No menu Ferramentas, selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes (PMC).
No PMC, execute o seguinte comando:
Install-Package Microsoft.EntityFrameworkCore.Design
Os comandos anteriores adicionam:
- O provedor EF Core do SQL Server. O pacote do provedor instala o pacote do EF Core como uma dependência.
- Os utilitários usados pelos pacotes instalados automaticamente na etapa de scaffolding, mais adiante no tutorial.
Compile o projeto como uma verificação de erros do compilador.
Aplicar scaffold a páginas de filme
Use a ferramenta scaffolding para produzir páginas CRUD (Create
, Read
, Update
e Delete
) para o modelo de filme.
Clique com o botão direito do mouse na pasta Controladores do Gerenciador de Soluções e selecione Adicionar > Novo Item Gerado por Scaffolding.
Na caixa de diálogo Adicionar Scaffold, selecione Controlador MVC com exibições, usando o Entity Framework > Adicionar.
Complete a caixa de diálogo Adicionar Controlador MVC com exibições, usando o Entity Framework:
- Na lista suspensa Classe de modelo, selecione Filme (MvcMovie.Models).
- Na linha Classe de contexto de dados, selecione o sinal + (adição).
- Na caixa de diálogo Adicionar Contexto de Dados , o nome da classe MvcMovie.Data.MvcMovieContext é gerado.
- Selecione Adicionar.
- Exibições e Nome do controlador: mantenha o padrão.
- Selecione Adicionar.
O scaffolding 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
Startup.ConfigureServices
do arquivoStartup.cs
. - Adiciona uma cadeia de caracteres de conexão do banco de dados ao arquivo
appsettings.json
.
O scaffolding cria o seguinte:
- Um controlador de filmes:
Controllers/MoviesController.cs
- Razor exibir arquivos para páginas Criar, Excluir, Detalhes, Editar e Índice :
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 scaffolding ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link Aplicativo de Filme resulta em uma mensagem de erro Não é possível abrir o banco de dados ou nenhuma tabela desse tipo: filme.
Migração inicial
Use o recurso EF CoreMigrações para criar o banco de dados. O recurso Migrações é um conjunto de ferramentas que cria e atualiza um banco de dados para corresponder ao modelo de dados.
No menu Ferramentas, selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes.
No PMC (Console do Gerenciador de Pacotes), Insira os seguintes comandos:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: gera um arquivo de migraçãoMigrations/{timestamp}_InitialCreate.cs
. O argumentoInitialCreate
é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, um nome que descreve a migração é selecionado. Como essa é a primeira migração, a classe gerada contém o código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classeMvcMovieContext
.Update-Database
: atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Esse comando executa o métodoUp
no arquivoMigrations/{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 valores sejam truncados silenciosamente se não couberem na precisão e na escala padrão. Especifique explicitamente o tipo de coluna do SQL Server 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, veja a referência de ferramentas de EF Core – PMC no Visual Studio.
Testar o aplicativo
Execute o aplicativo e clique no link Aplicativo de Filme.
Se você receber uma exceção semelhante à seguinte, talvez tenha perdido a etapa de migrações:
SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.
Observação
Talvez você não consiga inserir casas decimais ou vírgulas no campo Price
. Para dar suporte à validação do jQuery para localidades com idiomas diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data diferentes do inglês dos EUA, o aplicativo precisa ser globalizado. Para obter instruções sobre a globalização, consulte esse problema no GitHub.
Examinar a classe de contexto e o registro do banco de dados gerados
Com o EF Core, o acesso aos dados é executado usando um modelo. Um modelo é feito 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 de banco de dados é derivado de Microsoft. EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
O scaffolding cria a classe de contexto do 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.
O ASP.NET Core foi criado com a DI (injeção de dependência). Serviços, como o contexto do banco de dados, devem ser registrados com DI no Startup
. Os componentes que necessitam desses serviços são fornecidos através dos parâmetros do construtor.
No arquivo Controllers/MoviesController.cs
, o construtor usa a Injeção de Dependência para injetar o contexto do banco de dados MvcMovieContext
no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
O scaffolding gerou 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 sistema de configuração ASP.NET Core faz a leitura da cadeia de caracteres de conexão de banco de dados "MvcMovieContext".
Examinar a cadeia de caracteres de conexão de banco de dados gerada
O 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"
}
}
No desenvolvimento local, o sistema de configuração do ASP.NET Core lê a chave ConnectionString
do arquivo appsettings.json
.
A classe InitialCreate
Examinar 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 de Filmes e configuraId
como a chave primária.- O método
InitialCreate.Down
reverte as alterações de esquema feitas pela migração deUp
.
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 a Injeção de Dependência para injetar o contexto de banco de dados (MvcMovieContext
) no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
Teste a página Criar. Inserir e enviar dados.
Teste os links Editar, Detalhes e Excluir.
Modelos fortemente tipados e a diretiva @model
Anteriormente neste 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 de associação tardia para passar informações para uma exibição.
O MVC também 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 scaffolding passou um modelo fortemente tipado na classe e nas exibições de MoviesController
.
Examine o método de 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 controlador
movies
, o primeiro segmento da URL. - A ação para
details
, o segundo segmento da URL. - O
id
para 1, o último segmento da 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 que permite valor nulo (int?
) nos casos em que o valor de id
não seja fornecido.
Um expressão lambda é passada para o método FirstOrDefaultAsync para selecionar as entidades de filmes que correspondem ao valor dos dados da rota ou da cadeia de consulta.
var movie = await _context.Movie
.FirstOrDefaultAsync(m => m.Id == id);
Se for encontrado um filme, uma instância do modelo Movie
será passada para a exibição Details
:
return View(movie);
Examinar 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 exibição especifica o tipo de objeto que a exibição espera. Quando o controlador de filme foi criado, a seguinte instrução @model
foi incluída:
@model MvcMovie.Models.Movie
Essa diretiva @model
permite o acesso ao filme que o controlador passou para a exibição. O objeto Model
é fortemente tipado. Por exemplo, na exibição Details.cshtml
, o código passa cada campo de filme para os Auxiliares de HTML DisplayNameFor
e DisplayFor
com o objeto fortemente tipado Model
. Os métodos Create
e Edit
e as exibições também passam um objeto de modelo Movie
.
Examine a exibição Index.cshtml
e o método Index
no controlador Filmes. Observe como o código cria um objeto List
quando ele chama o método View
. O código passa esta lista 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
na parte superior do arquivo Index.cshtml
:
@model IEnumerable<MvcMovie.Models.Movie>
A diretiva @model
permite acessar a lista de filmes que o controlador passou para a exibição usando um objeto Model
fortemente tipado. Por exemplo, na exibição Index.cshtml
o código executa um loop pelos filmes com uma instrução foreach
no 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.
Registro em log do SQL do Entity Framework Core
A configuração de log geralmente é fornecida pela seção Logging
dos arquivos appsettings.{Environment}.json
. Para registrar instruções SQL em log, 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 Registrando em log no .NET Core e no ASP.NET Core e este tópico do GitHub.
Recursos adicionais
Neste tutorial, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes serão a parte do “Modelo” parte do aplicativo MVC.
Essas classes do modelo são usadas com o Entity Framework Core (EF Core) para trabalhar com um banco de dados. O EF Core é uma estrutura ORM (mapeamento relacional de objetos) 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 (Bons e velhos objetos do CLR). As classes POCO não têm nenhuma dependência em EF Core. Elas definem as propriedades dos dados a serem armazenados no banco de dados.
Neste tutorial, você escreve as classes de modelo primeiro e o EF Core cria o banco de dados.
Adicionar uma classe de modelo de dados
Clique com o botão direito do mouse na pasta Modelos >Adicionar>Classe. Dê o nome Movie.cs
para o arquivo.
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 esse atributo:
- O usuário não precisa inserir informações de tempo no campo de data.
- Somente a data é exibida, não as informações de tempo.
DataAnnotations são abordados em um tutorial posterior.
Adicionar pacotes do NuGet
No menu Ferramentas, selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes (PMC).
No PMC, execute o seguinte comando:
Install-Package Microsoft.EntityFrameworkCore.SqlServer
O comando anterior adiciona o provedor SQL Server do EF Core. O pacote do provedor instala o pacote do EF Core como uma dependência. Pacotes adicionais são instalados automaticamente na etapa de scaffolding posteriormente no tutorial.
Criar uma classe de contexto de banco de dados
Uma classe de contexto de banco de dados é necessária para coordenar a funcionalidade do EF Core (Criar, Ler, Atualizar, Excluir) para o modelo Movie
. O contexto de banco de dados é derivado de Microsoft.EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
Crie uma pasta de Dados.
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 da tabela.
Registrar o contexto de banco de dados
O ASP.NET Core foi criado com a DI (injeção de dependência). Os serviços (como o contexto de banco de dados do EF Core) devem ser registrados com a DI durante a inicialização do aplicativo. Os componentes que exigem esses serviços (por exemplo, o Razor Pages) são fornecidos por meio dos parâmetros do construtor. O código de construtor que obtém uma instância de contexto do BD será mostrado mais adiante no tutorial. Nesta seção, você registra o contexto do banco de dados com o contêiner DI.
Adicione as seguintes instruções do using
na parte superior do Startup.cs
:
using MvcMovie.Data;
using Microsoft.EntityFrameworkCore;
Adicione o código realçado a seguir a 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 com a chamada de um método em um objeto DbContextOptions. Para o desenvolvimento local, o sistema de configuração do ASP.NET Core lê a cadeia de conexão do arquivo appsettings.json
.
Examine a cadeia de caracteres de conexão de banco de dados
Adicione uma cadeia de caracteres 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"
}
}
Compile o projeto como uma verificação de erros do compilador.
Aplicar scaffold a páginas de filme
Use a ferramenta scaffolding 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 com Scaffolding.
Na caixa de diálogo Adicionar Scaffold, selecione Controlador MVC com exibições, usando o Entity Framework > Adicionar.
Preencha a caixa de diálogo Adicionar Controlador:
- Classe de modelo: Movie (MvcMovie.Models)
- Classe de contexto de dados: MvcMovieContext (MvcMovie.Data)
- Exibições: mantenha o padrão de cada opção marcado
- Nome do controlador: mantenha o MoviesController padrão
- Selecione Adicionar
O Visual Studio cria:
- Um controlador de filmes (
Controllers/MoviesController.cs
) - Exibição de Razor para Criar, Excluir, Detalhes, Editar e Índice de páginas ("Views/Movies/`.cshtml)
A criação automática desses arquivos é conhecida como scaffolding.
Você não pode usar as páginas com scaffold ainda porque o banco de dados não existe. Se você executar o aplicativo e clicar no link Aplicativo de Filme, obterá uma mensagem de erro Não é possível abrir o banco de dados ou Não há uma tabela assim: Filme.
Migração inicial
Use o recurso EF CoreMigrações para criar o banco de dados. As migrações são um conjunto de ferramentas que permitem criar e atualizar um banco de dados para corresponder ao seu modelo de dados.
No menu Ferramentas, selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes (PMC).
No PMC, insira os seguintes comandos:
Add-Migration InitialCreate
Update-Database
Add-Migration InitialCreate
: gera um arquivo de migraçãoMigrations/{timestamp}_InitialCreate.cs
. O argumentoInitialCreate
é o nome da migração. Qualquer nome pode ser usado, mas, por convenção, um nome que descreve a migração é selecionado. Como essa é a primeira migração, a classe gerada contém o código para criar o esquema de banco de dados. O esquema de banco de dados é baseado no modelo especificado na classeMvcMovieContext
.Update-Database
: atualiza o banco de dados para a migração mais recente, que o comando anterior criou. Esse comando executa o métodoUp
no arquivoMigrations/{time-stamp}_InitialCreate.cs
, que cria o banco de dados.O comando de atualização de banco de dados gera o seguinte aviso:
Nenhum tipo foi especificado para a coluna decimal 'Preço' no tipo de entidade 'Filme'. Isso fará com que valores sejam truncados silenciosamente se não couberem na precisão e na escala padrão. Especifique explicitamente o tipo de coluna do SQL Server 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, veja a referência de ferramentas de EF Core – PMC no Visual Studio.
A classe InitialCreate
Examinar 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 de filmes e configura Id
como a chave primária. O método Down
reverte as alterações de esquema feitas pela migração Up
.
Testar o aplicativo
Execute o aplicativo e clique no link Aplicativo de Filme.
Se você receber uma exceção semelhante a uma das seguintes:
SqlException: Cannot open database "MvcMovieContext-1" requested by the login. The login failed.
Você provavelmente perdeu a etapa de migrações.
Teste a página Criar. Inserir e enviar dados.
Observação
Talvez você não consiga inserir casas decimais ou vírgulas no campo
Price
. Para dar suporte à validação do jQuery para localidades com idiomas diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data diferentes do inglês dos EUA, o aplicativo precisa ser globalizado. Para obter instruções sobre a globalização, consulte esse problema no GitHub.Teste os links Editar, Detalhes e Excluir.
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 a Injeção de Dependência para injetar o contexto de banco de dados (MvcMovieContext
) no controlador. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.
Modelos fortemente tipados e a palavra-chave @model
Anteriormente neste 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 de associação tardia para passar informações para uma exibição.
O MVC também 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 scaffolding usou essa abordagem (ou seja, passando um modelo fortemente tipado) com a classe MoviesController
e as exibições.
Examine o método de 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 controlador
movies
(o primeiro segmento de URL). - A ação para
details
(o segundo segmento de URL). - A ID como 1 (o último segmento de URL).
Você também pode passar a id
com uma cadeia de consulta da seguinte maneira:
https://localhost:5001/movies/details?id=1
O parâmetro id
é definido como um tipo que permite valor nulo (int?
), caso um valor de ID não seja fornecido.
Um expressão lambda é passada para FirstOrDefaultAsync
para selecionar as entidades de filmes que correspondem ao valor da cadeia de consulta ou de dados da rota.
var movie = await _context.Movie
.FirstOrDefaultAsync(m => m.Id == id);
Se for encontrado um filme, uma instância do modelo Movie
será passada para a exibição Details
:
return View(movie);
Examinar 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 exibição especifica o tipo de objeto que a exibição espera. Quando o controlador de filme foi criado, a seguinte instrução @model
foi incluída:
@model MvcMovie.Models.Movie
Essa diretiva @model
permite o acesso ao filme que o controlador passou para a exibição. O objeto Model
é fortemente tipado. Por exemplo, na exibição Details.cshtml
, o código passa cada campo de filme para os Auxiliares de HTML DisplayNameFor
e DisplayFor
com o objeto fortemente tipado Model
. Os métodos Create
e Edit
e as exibições também passam um objeto de modelo Movie
.
Examine a exibição Index.cshtml
e o método Index
no controlador Filmes. Observe como o código cria um objeto List
quando ele chama o método View
. O código passa esta lista 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
na parte superior do arquivo Index.cshtml
:
@model IEnumerable<MvcMovie.Models.Movie>
A diretiva @model
permite acessar a lista de filmes que o controlador passou para a exibição usando um objeto Model
fortemente tipado. Por exemplo, na exibição Index.cshtml
o código executa um loop pelos filmes com uma instrução foreach
no 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 a verificação do tempo de compilação do código.