Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Note
Esta não é a versão mais recente deste artigo. Para ver a versão atual, consulte a versão .NET 10 deste artigo.
Warning
Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, consulte o .NET e .NET Core Support Policy. Para ver a versão atual, consulte a versão .NET 10 deste artigo.
Neste tutorial, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes são a parte do "Model" do aplicativo MVC.
Essas classes de modelo são usadas com 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 do tipo POCO, de Plain Old CLR Objects (Objetos CLR Simples). 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
Visual Studio instala automaticamente os pacotes necessários.
Compile o projeto como uma verificação de erros do compilador.
Estruturar páginas de filmes
Use a ferramenta de scaffolding para produzir páginas (Create, Read, Update e Delete) CRUD para o modelo de filme.
Em Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controllers e selecione Adicionar > Novo Item Escafoldado.
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 o diálogo Adicionar Controlador MVC com visõ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.
Adicionar contexto de dados, mantendo os padrões.
Se você receber uma mensagem de erro, selecione Adicionar uma segunda vez para tentar novamente.
Scaffolding adiciona os seguintes pacotes:
Microsoft.EntityFrameworkCore.SqlServerMicrosoft.EntityFrameworkCore.ToolsMicrosoft.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. - Adiciona uma cadeia de conexão de banco de dados ao arquivo
appsettings.json.
A criação automática desses arquivos e atualizações de arquivos é conhecida como scaffolding.
As páginas geradas automaticamente ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link Movie App resulta em uma mensagem de erro Não é possível abrir o banco de dados ou no such table: Movie.
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 Tools, selecione NuGet Gerenciador de Pacotes>Gerenciador de Pacotes Console.
No PMC (Console 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 armazenamento foi especificado para a propriedade 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 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étodoUpno arquivoMigrations/{time-stamp}_InitialCreate.cs, que cria o banco de dados.
Para obter mais informações sobre as ferramentas do PMC para EF Core, consulte EF Core tools reference - PMC in 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.
Note
Talvez você não consiga inserir vírgulas decimais no campo Price. Para dar suporte à validação do jQuery para localidades não anglófonas 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 de globalização, consulte este problema do 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 do 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
ASP.NET Core é criado com injeção de dependência (DI). 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.
A geração de código scaffolding produziu o seguinte código destacado em Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<MvcMovieContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext") ?? throw new InvalidOperationException("Connection string 'MvcMovieContext' not found.")));
O sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".
Examinar a cadeia de conexão do banco de dados gerado
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"
}
}
Para desenvolvimento local, o sistema de configuração 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.Upcria a tabela de Filmes e configuraIdcomo a chave primária. - O método
InitialCreate.Downreverte 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 ligação tardia para passar informações para uma visã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 do código durante o tempo de compilação. O mecanismo de scaffolding passou um modelo fortemente tipado na classe MoviesController e nas visõ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:{PORT}/movies/details/1 define:
- O controlador em relação ao controlador
movies, o primeiro segmento da URL. - A ação para
details, o segundo segmento da URL. - O
idaté 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:{PORT}/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.
Uma 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 string 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 passam também 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 visualização Index.cshtml, o código executa um loop pelos filmes com uma instrução foreach no objeto fortemente tipado Model.
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Como o objeto Model é fortemente tipado como um objeto IEnumerable<Movie>, cada item no loop é tipado como Movie. Entre outros benefícios, o compilador valida os tipos usados no código.
Recursos adicionais
Neste tutorial, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes são a parte "Modelo" do aplicativo MVC.
Essas classes de modelo são usadas com 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, que significa "Plain Old CLR Objects" (simples e antigos objetos 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
Visual Studio instala automaticamente os pacotes necessários.
Compile o projeto como uma verificação de erros do compilador.
Estruturar páginas de filme
Use a ferramenta de scaffolding para produzir Create, Read, Update e Delete (páginas CRUD) para o modelo de filme.
Em Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controllers e selecione Add > Novo Item Scaffolded.
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 visõ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 Database provider, 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.
Scaffolding adiciona os seguintes pacotes:
Microsoft.EntityFrameworkCore.SqlServerMicrosoft.EntityFrameworkCore.ToolsMicrosoft.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. - Adiciona uma string de conexão de banco de dados ao arquivo
appsettings.json.
A criação automática desses arquivos e atualizações de arquivos é conhecida como scaffolding.
As páginas estruturadas ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link Movie App resulta em uma mensagem de erro Não é possível abrir o banco de dados ou nenhuma tabela desse tipo: Movie.
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 Tools, selecione NuGet Gerenciador de Pacotes>Gerenciador de Pacotes Console.
No PMC (Console 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 armazenamento foi especificado para a propriedade 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 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étodoUpno arquivoMigrations/{time-stamp}_InitialCreate.cs, que cria o banco de dados.
Para obter mais informações sobre as ferramentas do PMC para EF Core, consulte EF Core tools reference - PMC in 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.
Note
Talvez você não consiga inserir vírgulas decimais no campo Price. Para dar suporte à validação do jQuery para localidades não anglófonas 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 de globalização, consulte este issue do 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 do banco de dados é derivado de Microsoft. EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
Scaffolding cria a classe de contexto 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
ASP.NET Core é criado com injeção de dependência (DI). 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 scaffold gerou o seguinte código destacado em Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<MvcMovieContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext") ?? throw new InvalidOperationException("Connection string 'MvcMovieContext' not found.")));
O sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".
Examinar a string de conexão de 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"
}
}
Para desenvolvimento local, o sistema de configuração 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.Upcria a tabela de Filmes e configuraIdcomo a chave primária. - O método
InitialCreate.Downreverte 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 ligação tardia para passar informações para uma visualizaçã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 MoviesController e nas visualizações associadas.
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:{PORT}/movies/details/1 define:
- O controlador para
movies, o primeiro segmento da URL. - A ação para
details, o segundo segmento da URL. - O
iddefinido 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:{PORT}/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.
Uma 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 string 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 transfere cada campo do filme para os Helpers 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 são a parte “Modelo” do aplicativo MVC.
Essas classes de modelo são usadas com 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 do tipo POCO, de Plain Old CLR Objects (Objetos CLR Simples). 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 é nula. Para obter mais informações, confira Tipos de referência anuláveis.
Adicionar pacotes do NuGet
Visual Studio instala automaticamente os pacotes necessários.
Compile o projeto como uma verificação de erros do compilador.
Estruturar páginas de filmes
Use a ferramenta de scaffolding para gerar páginas CRUD (Create, Read, Update e Delete) para o modelo de filme.
Em Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controllers e selecione Adicionar > Novo Item Scaffoldado.
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.
Preencha a caixa de diálogo Adicionar Controlador MVC com visõ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.
Scaffolding adiciona os seguintes pacotes:
Microsoft.EntityFrameworkCore.SqlServerMicrosoft.EntityFrameworkCore.ToolsMicrosoft.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. - Adiciona uma cadeia de conexão de banco de dados ao arquivo
appsettings.json.
A criação automática desses arquivos e atualizações de arquivos é conhecida como scaffolding.
As páginas scaffoldadas ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link Aplicativo de Filmes resulta em uma mensagem de erro Não é possível abrir o banco de dados ou não existe tal tabela: Movie.
Crie o aplicativo para verificar se não há erros.
Migração inicial
Use o recurso EF CoreMigrações para criar 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 Tools, selecione NuGet Gerenciador de Pacotes>Gerenciador de Pacotes Console.
No PMC (Console 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étodoUpno arquivoMigrations/{time-stamp}_InitialCreate.cs, que cria o banco de dados.
O comando Update-Database gera o seguinte aviso:
Nenhum tipo de armazenamento foi especificado para a propriedade 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 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 do PMC para EF Core, consulte EF Core tools reference - PMC in 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.
Note
Talvez você não consiga inserir vírgulas decimais no campo Price. Para dar suporte à validação do jQuery para localidades não anglófonas 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 de globalização, consulte este issue do 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 do banco de dados é derivado de Microsoft. EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
Scaffolding cria a classe de contexto 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
ASP.NET Core é criado com injeção de dependência (DI). 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 scaffold gerou o seguinte código destacado em Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<MvcMovieContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));
O sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".
Examinar a string 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"
}
}
Para desenvolvimento local, o sistema de configuração 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.Upcria a tabela de Filmes e configuraIdcomo a chave primária. - O método
InitialCreate.Downreverte 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 vinculaçã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 durante a compilação. O mecanismo de scaffolding passou um modelo fortemente tipado na classe MoviesController e nas views.
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
movies, o primeiro segmento da URL. - A ação para
details, o segundo segmento da URL. -
idpara 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.
Uma 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 percorre os filmes com uma instrução foreach sobre o objeto Model fortemente tipado.
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Como o objeto Model é fortemente tipado como um objeto IEnumerable<Movie>, cada item no loop é tipado como Movie. Entre outros benefícios, o compilador valida os tipos usados no código.
Recursos adicionais
Neste tutorial, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes são a parte "Model" do aplicativo MVC.
Essas classes de modelo são usadas com 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 (Plain Old CLR Objects). 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 é nula. Para obter mais informações, confira Tipos de referência anuláveis.
Adicionar pacotes do NuGet
Visual Studio instala automaticamente os pacotes necessários.
Compile o projeto como uma verificação de erros do compilador.
Estruturar páginas de filme
Use a ferramenta de scaffolding para produzir Create, Read, Update e Delete (páginas CRUD) para o modelo de filme.
Em Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controllers e selecione Add > Novo Item Scaffolded.
No diálogo Adicionar Novo Item Estruturado:
- 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.SqlServerMicrosoft.EntityFrameworkCore.ToolsMicrosoft.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. - Adiciona uma cadeia de conexão de banco de dados ao arquivo
appsettings.json.
A criação automática desses arquivos e atualizações de arquivos é conhecida como scaffolding.
As páginas geradas com scaffolding ainda não podem ser usadas porque o banco de dados não existe. Executar o app e selecionar o link Movie App resulta em uma mensagem de erro Não é possível abrir o banco de dados ou não existe tal tabela: Movie.
Crie o aplicativo para verificar se não há erros.
Migração inicial
Use o recurso EF CoreMigrações para criar 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 Tools, selecione NuGet Gerenciador de Pacotes>Console do Gerenciador de Pacotes.
No PMC (Console 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étodoUpno 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 do PMC para EF Core, consulte EF Core tools reference - PMC in 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.
Note
Talvez você não consiga inserir vírgulas decimais no campo Price. Para dar suporte à validação do jQuery para localidades não anglófonas 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 de globalização, consulte este problema do 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 do 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
ASP.NET Core é criado com injeção de dependência (DI). 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.
A geração de código scaffolding produziu o seguinte código destacado em Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<MvcMovieContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));
O sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".
Examinar a cadeia de conexão do banco de dados gerado
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"
}
}
Para desenvolvimento local, o sistema de configuração 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.Upcria a tabela de Filmes e configuraIdcomo a chave primária. - O método
InitialCreate.Downreverte 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 ligação tardia para passar informações para uma visã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 MoviesController e nas visualizações associadas.
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
movies, o primeiro segmento da URL. - A ação para
details, o segundo segmento da URL. - O
iddefinido 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.
Uma 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 string 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 transfere cada campo do filme para os Helpers 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 são a parte “Modelo” do aplicativo MVC.
Essas classes de modelo são usadas com 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 do tipo POCO, de Plain Old CLR Objects (Objetos CLR Simples). 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 Tools, selecione NuGet Gerenciador de Pacotes>Gerenciador de Pacotes Console (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 SQL Server. O pacote provedor instala o pacote EF Core como dependência.
- Os utilitários usados pelos pacotes instalados automaticamente na etapa de estruturamento, mais adiante no tutorial.
Compile o projeto como uma verificação de erros do compilador.
Criar estrutura para páginas de filme
Use a ferramenta de scaffolding para produzir páginas Create, Read, Update e Delete (CRUD) para o modelo de filme.
Em Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controllers e selecione Adicionar > Novo Item Estruturado.
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 um Controlador MVC com exibições de interface, 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 conexão de 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 geradas automaticamente ainda não podem ser usadas porque o banco de dados não existe. Executar o aplicativo e selecionar o link Movie App resulta em uma mensagem de erro Não é possível abrir o banco de dados ou no such table: Movie.
Criar o aplicativo
Crie o aplicativo. O compilador gera vários avisos sobre como os valores de null são tratados. Consulte este problema do GitHub e tipos de referência anuláveis para 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 Tools, selecione NuGet Gerenciador de Pacotes>Console do Gerenciador de Pacotes.
No PMC (Console 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étodoUpno 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 do PMC para EF Core, consulte EF Core tools reference - PMC in 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.
Note
Talvez você não consiga inserir vírgulas decimais no campo Price. Para dar suporte à validação do jQuery para localidades não anglófonas 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 de globalização, consulte este issue do 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 do banco de dados é derivado de Microsoft. EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
Scaffolding cria a classe de contexto 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
ASP.NET Core é criado com injeção de dependência (DI). 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 scaffold gerou o seguinte código destacado em Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<MvcMovieContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext")));
O sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".
Examinar a cadeia de conexão do banco de dados gerado
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"
}
}
Para desenvolvimento local, o sistema de configuração 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.Upcria a tabela de Filmes e configuraIdcomo a chave primária. - O método
InitialCreate.Downreverte 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 ligação tardia para passar informações para uma visã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 do código durante o tempo de compilação. O mecanismo de scaffolding passou um modelo fortemente tipado na classe MoviesController e nas visõ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 em relação ao controlador
movies, o primeiro segmento da URL. - A ação para
details, o segundo segmento da URL. - O
idaté 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.
Uma 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 string 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 percorre os filmes com uma instrução foreach sobre o objeto Model fortemente tipado.
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Como o objeto Model é fortemente tipado como um objeto IEnumerable<Movie>, cada item no loop é tipado como Movie. Entre outros benefícios, o compilador valida os tipos usados no código.
Recursos adicionais
Neste tutorial, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes são a parte do "Model" do aplicativo MVC.
Essas classes de modelo são usadas com 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 do tipo POCO, de Plain Old CLR Objects (Objetos CLR Simples). 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 Tools, selecione NuGet Gerenciador de Pacotes>Gerenciador de Pacotes Console (PMC).
No PMC, execute o seguinte comando:
Install-Package Microsoft.EntityFrameworkCore.Design
Os comandos anteriores adicionam:
- Provedor de SQL Server EF Core. O pacote do provedor instala, como uma dependência, o pacote do EF Core.
- Os utilitários usados pelos pacotes instalados automaticamente na etapa de estruturação serão utilizados posteriormente no tutorial.
Compile o projeto como uma verificação de erros do compilador.
Estruturar páginas de filmes
Use a ferramenta de scaffolding para produzir Create, Read, Update e Delete (páginas CRUD) para o modelo de filme.
Em Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controllers e selecione Add > Novo Item Scaffolded.
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.ConfigureServicesdo arquivoStartup.cs. - Adiciona uma string de conexão de 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 a base de dados ou nenhuma tabela desse tipo: Movie.
Migração inicial
Use o recurso EF CoreMigrações para criar o banco de dados. As ferramentas de migração são um conjunto de ferramentas que criam e atualizam um banco de dados para corresponder ao modelo de dados.
No menu Tools, selecione NuGet Gerenciador de Pacotes>Console do Gerenciador de Pacotes.
No PMC (Console 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étodoUpno 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 do PMC para EF Core, consulte EF Core tools reference - PMC in 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.
Note
Talvez você não consiga inserir vírgulas decimais no campo Price. Para dar suporte à validação do jQuery para localidades não anglófonas 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 de globalização, consulte este issue do 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 do banco de dados é derivado de Microsoft. EntityFrameworkCore.DbContext e especifica as entidades a serem incluídas no modelo de dados.
Scaffolding cria a classe de contexto 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.
ASP.NET Core é criado com injeção de dependência (DI). 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 scaffold gerou o seguinte código destacado em Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<MvcMovieContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MvcMovieContext")));
}
O sistema de configuração ASP.NET Core lê a cadeia de conexão do banco de dados "MvcMovieContext".
Examinar a string de conexão de 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"
}
}
Para desenvolvimento local, o sistema de configuração 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.Upcria a tabela de Filmes e configuraIdcomo a chave primária. - O método
InitialCreate.Downreverte 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 ligação tardia para passar informações para uma visã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 do código durante o tempo de compilação. O mecanismo de scaffolding passou um modelo fortemente tipado na classe MoviesController e nas visõ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 em relação ao controlador
movies, o primeiro segmento da URL. - A ação para
details, o segundo segmento da URL. - O
idaté 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.
Uma 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 string 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 percorre os filmes com uma instrução foreach sobre o objeto Model fortemente tipado.
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Como o objeto Model é fortemente tipado como um objeto IEnumerable<Movie>, cada item no loop é tipado como Movie. Entre outros benefícios, o compilador valida os tipos usados no código.
Registro em log sql de 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 Visual Studio.
Para obter mais informações, consulte os seguintes recursos:
- Log em .NET e ASP.NET Core
-
ASP.NET template desabilita EF Core registro em log SQL por padrão (
dotnet/aspnetcore#32977)
Recursos adicionais
Neste tutorial, classes são adicionadas para o gerenciamento de filmes em um banco de dados. Essas classes são a parte do "Model" do aplicativo MVC.
Essas classes de modelo são usadas com 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 do tipo POCO, de Plain Old CLR Objects (Objetos CLR Simples). 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 Tools, selecione NuGet Gerenciador de Pacotes>Gerenciador de Pacotes Console (PMC).
No PMC, execute o seguinte comando:
Install-Package Microsoft.EntityFrameworkCore.SqlServer
O comando anterior adiciona o provedor EF Core SQL Server. O pacote do provedor instala o pacote EF Core como uma dependência. Pacotes adicionais são instalados automaticamente na etapa de estruturação 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 do 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
ASP.NET Core é criado com injeção de dependência (DI). Os serviços (como o contexto de banco de dados do EF Core) devem ser registrados na DI durante o início 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 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 do cadeia de conexão é passado para o contexto chamando um método em um objeto DbContextOptions. Para desenvolvimento local, o sistema de configuração ASP.NET Core lê o cadeia de conexão do arquivo appsettings.json.
Examinar a cadeia de conexão do banco de dados
Adicione um 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"
}
}
Compile o projeto como uma verificação de erros do compilador.
Estruturar páginas de filmes
Use a ferramenta scaffolding para produzir páginas CRUD (criar, ler, atualizar e excluir) para o modelo de filme.
Em Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controllers> Adicionar > Novo Item Estruturado.
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 cada opção com sua configuração padrão marcada
- Nome do controlador: mantenha o MoviesController padrão
- Selecione Adicionar
Visual Studio cria:
- Um controlador de filmes (
Controllers/MoviesController.cs) - Ver arquivos para Criar, Excluir, Detalhes, Editar e Página de Índice (RazorViews/Movies/`.cshtml`)
A criação automática desses arquivos é conhecida como scaffolding.
Você não pode usar as páginas geradas automaticamente 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 Tools, selecione NuGet Gerenciador de Pacotes>Gerenciador de Pacotes Console (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étodoUpno 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 do PMC para EF Core, consulte EF Core tools reference - PMC in 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.
Note
Talvez você não consiga inserir vírgulas decimais no campo
Price. Para dar suporte à validação do jQuery para localidades não anglófonas 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 de globalização, consulte este issue do 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 dinâmica para passar informações para uma visualização.
O MVC também fornece a capacidade de passar objetos de modelo fortemente tipados para uma exibição. Essa abordagem de tipagem forte permite a verificação de código em tempo de compilação. O mecanismo de scaffolding usou essa abordagem (isto é, passando um modelo fortemente tipado) com a classe MoviesController e as visõ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 relacionado ao controlador
movies(o primeiro segmento de URL). - A ação para
details(o segundo segmento de URL). - O ID para 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 percorre os filmes com uma instrução foreach sobre o objeto Model fortemente tipado.
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Como o objeto Model é fortemente tipado (como um objeto IEnumerable<Movie>), cada item no loop é tipado como Movie. Entre outros benefícios, isso significa que você obtém a verificação do tempo de compilação do código.