Adicione um modelo a um aplicativo ASP.NET Core MVCAdd a model to an ASP.NET Core MVC app

Por Rick Anderson e Tom DykstraBy Rick Anderson and Tom Dykstra

Nesta seção, você adicionará algumas classes para o gerenciamento de filmes em um banco de dados.In this section, you'll add some classes for managing movies in a database. Essas classes serão a parte “Model” parte do aplicativo MVC.These classes will be the "Model" part of the MVC app.

Você usa essas classes com o EF Core (Entity Framework Core) para trabalhar com um banco de dados.You use these classes with Entity Framework Core (EF Core) to work with a database. O EF Core é uma estrutura ORM (mapeamento relacional de objetos) que simplifica o código de acesso a dados que você precisa escrever.EF Core is an object-relational mapping (ORM) framework that simplifies the data access code that you have to write. O EF Core dá suporte a vários mecanismos de banco de dados.EF Core supports many database engines.

As classes de modelo que serão criadas são conhecidas como classes POCO (de “objetos CLR básicos”) porque elas não têm nenhuma dependência do EF Core.The model classes you'll create are known as POCO classes (from "plain-old CLR objects") because they don't have any dependency on EF Core. Elas apenas definem as propriedades dos dados que serão armazenados no banco de dados.They just define the properties of the data that will be stored in the database.

Neste tutorial, você escreverá as classes de modelo primeiro e o EF Core criará o banco de dados.In this tutorial you'll write the model classes first, and EF Core will create the database. Uma abordagem alternativa não abordada aqui é gerar classes de modelo com base em um banco de dados já existente.An alternate approach not covered here is to generate model classes from an already-existing database. Para obter informações sobre essa abordagem, consulte ASP.NET Core – Banco de dados existente.For information about that approach, see ASP.NET Core - Existing Database.

Adicionar uma classe de modelo de dadosAdd a data model class

Clique com o botão direito do mouse na pasta Models > Adicionar > Classe.Right-click the Models folder > Add > Class. Nomeie a classe Movie e adicione as seguintes propriedades:Name the class Movie and add the following properties:

using System;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; }
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

O campo ID é necessário para o banco de dados para a chave primária.The ID field is required by the database for the primary key.

Compile o projeto para verificar se não há erros.Build the project to verify you don't have any errors. Agora você tem um Modelo no aplicativo MVC.You now have a Model in your MVC app.

Gerando um controlador por scaffoldingScaffolding a controller

No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controladores > Adicionar > Novo Item com Scaffold.In Solution Explorer, right-click the Controllers folder > Add > New Scaffolded Item.

exibição da etapa acima

Na caixa de diálogo Adicionar Scaffold, toque em Controlador MVC com exibições, usando o Entity Framework > Adicionar.In the Add Scaffold dialog, tap MVC Controller with views, using Entity Framework > Add.

Caixa de diálogo Adicionar Scaffold

No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controllers > Adicionar > Controlador.In Solution Explorer, right-click the Controllers folder > Add > Controller.

exibição da etapa acima

Se a caixa de diálogo Adicionar Dependências do MVC for exibida:If the Add MVC Dependencies dialog appears:

Na caixa de diálogo Adicionar Scaffold, toque em Controlador MVC com exibições, usando o Entity Framework > Adicionar.In the Add Scaffold dialog, tap MVC Controller with views, using Entity Framework > Add.

Caixa de diálogo Adicionar Scaffold

Preencha a caixa de diálogo Adicionar Controlador:Complete the Add Controller dialog:

  • Classe de modelo: Movie (MvcMovie.Models)Model class: Movie (MvcMovie.Models)
  • Classe de contexto de dados: selecione o ícone + e adicione o MvcMovie.Models.MvcMovieContext padrãoData context class: Select the + icon and add the default MvcMovie.Models.MvcMovieContext

Adicionar contexto de dados

  • Exibições: mantenha o padrão de cada opção marcadoViews: Keep the default of each option checked
  • Nome do controlador: mantenha o MoviesController padrãoController name: Keep the default MoviesController
  • Toque em AdicionarTap Add

Caixa de diálogo Adicionar Controlador

O Visual Studio cria:Visual Studio creates:

  • Uma classe de contexto de banco de dados do Entity Framework Core (Data/MvcMovieContext.cs)An Entity Framework Core database context class (Data/MvcMovieContext.cs)
  • Um controlador de filmes (Controllers/MoviesController.cs)A movies controller (Controllers/MoviesController.cs)
  • Arquivos de exibição do Razor para as páginas Criar, Excluir, Detalhes, Editar e Índice (Views/Movies/*.cshtml)Razor view files for Create, Delete, Details, Edit, and Index pages (Views/Movies/*.cshtml)

A criação automática do contexto de banco de dados e das exibições e métodos de ação CRUD (criar, ler, atualizar e excluir) é conhecida como scaffolding.The automatic creation of the database context and CRUD (create, read, update, and delete) action methods and views is known as scaffolding. Logo você terá um aplicativo Web totalmente funcional que permitirá que você gerencie um banco de dados de filmes.You'll soon have a fully functional web application that lets you manage a movie database.

Se você executar o aplicativo e clicar no link Filme do MVC, receberá um erro semelhante ao seguinte:If you run the app and click on the Mvc Movie link, you get an error similar to the following:

An unhandled exception occurred while processing the request.

SqlException: Cannot open database "MvcMovieContext-<GUID removed>" requested by the login. The login failed.
Login failed for user 'Rick'.

System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString 

Você precisa criar o banco de dados e usará o recurso Migrações do EF Core para fazer isso.You need to create the database, and you'll use the EF Core Migrations feature to do that. As Migrações permitem criar um banco de dados que corresponde ao seu modelo de dados e atualizar o esquema de banco de dados quando o modelo de dados é alterado.Migrations lets you create a database that matches your data model and update the database schema when your data model changes.

Adicionar ferramentas do EF e executar a migração inicialAdd EF tooling and perform initial migration

Nesta seção, você usará o PMC (Console de Gerenciador de Pacotes) para:In this section you'll use the Package Manager Console (PMC) to:

  • Adicione o pacote de Ferramentas do Entity Framework Core.Add the Entity Framework Core Tools package. Esse pacote é necessário adicionar migrações e atualizar o banco de dados.This package is required to add migrations and update the database.
  • Adicione uma migração inicial.Add an initial migration.
  • Atualize o banco de dados com a migração inicial.Update the database with the initial migration.

No menu Ferramentas, selecione Gerenciador de Pacotes NuGet > Console do Gerenciador de Pacotes.From the Tools menu, select NuGet Package Manager > Package Manager Console.

Menu do PMC PMC menu

No PMC, insira os seguintes comandos:In the PMC, enter the following commands:

Add-Migration Initial
Update-Database

Ignore a mensagem de erro a seguir, estamos corrigindo-a no próximo tutorial:Ignore the following error message, we fix it in the next tutorial:

Microsoft.EntityFrameworkCore.Model.Validation[30000]Microsoft.EntityFrameworkCore.Model.Validation[30000]
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 'ForHasColumnType()'.No type was specified for the decimal column 'Price' on entity type 'Movie'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values using 'ForHasColumnType()'.

Install-Package Microsoft.EntityFrameworkCore.Tools
Add-Migration Initial
Update-Database

Observação: se você receber um erro com o comando Install-Package, abra o Gerenciador de Pacotes NuGet e pesquise pelo pacote Microsoft.EntityFrameworkCore.Tools.Note: If you receive an error with the Install-Package command, open NuGet Package Manager and search for the Microsoft.EntityFrameworkCore.Tools package. Isso permite que você instale o pacote ou verifique se ele já está instalado.This allows you to install the package or check if it's already installed. Observação: consulte a abordagem da CLI caso você tenha problemas com o PMC.Alternatively, see the CLI approach if you have problems with the PMC.

O comando Add-Migration cria um código para criar o esquema de banco de dados inicial.The Add-Migration command creates code to create the initial database schema. O esquema é baseado no modelo especificado no DbContext (no arquivo Data/MvcMovieContext.cs).The schema is based on the model specified in the DbContext(In the Data/MvcMovieContext.cs file). O argumento Initial é usado para nomear as migrações.The Initial argument is used to name the migrations. Você pode usar qualquer nome, mas, por convenção, escolha um nome que descreve a migração.You can use any name, but by convention you choose a name that describes the migration. Consulte Introdução às migrações para obter mais informações.See Introduction to migrations for more information.

O comando Update-Database executa o método Up no arquivo Migrations/<time-stamp>_Initial.cs, que cria o banco de dados.The Update-Database command runs the Up method in the Migrations/<time-stamp>_Initial.cs file, which creates the database.

Execute as etapas anteriores usando a CLI (interface de linha de comando) em vez do PMC:You can perform the preceeding steps using the command-line interface (CLI) rather than the PMC:

  • Adicione as ferramentas do EF Core ao arquivo .csproj.Add EF Core tooling to the .csproj file.

  • Execute os seguintes comandos no console (no diretório do projeto):Run the following commands from the console (in the project directory):

    dotnet ef migrations add Initial
    dotnet ef database update
    

    Se você executar o aplicativo e obtiver o erro:If you run the app and get the error:

    SqlException: Cannot open database "Movie" requested by the login.
    The login failed.
    Login failed for user 'user name'.
    

Provavelmente você não terá executado dotnet ef database update.You probably have not run dotnet ef database update.

Testar o aplicativoTest the app

  • Execute o aplicativo e toque no link Filme Mvc.Run the app and tap the Mvc Movie link.

  • Toque no link Criar Novo e crie um filme.Tap the Create New link and create a movie.

    Criar exibição com campos para título, gênero, preço e data de lançamento

  • Talvez você não possa inserir pontos decimais ou vírgulas no campo Price.You may not be able to enter decimal points or commas in the Price field. Para dar suporte à validação do jQuery para localidades de idiomas diferentes do inglês que usam uma vírgula (“,”) para um ponto decimal e formatos de data diferentes do inglês dos EUA, você deve tomar medidas para globalizar o aplicativo.To support jQuery validation for non-English locales that use a comma (",") for a decimal point, and non US-English date formats, you must take steps to globalize your app. Veja https://github.com/aspnet/Docs/issues/4076 e Recursos adicionais para obter mais informações.See https://github.com/aspnet/Docs/issues/4076 and Additional resources for more information. Por enquanto, insira apenas números inteiros como 10.For now, just enter whole numbers like 10.

  • Em algumas localidades, você precisa especificar o formato da data.In some locales you need to specify the date format. Consulte o código realçado abaixo.See the highlighted code below.
using System;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; }
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

Falaremos sobre DataAnnotations posteriormente no tutorial.We'll talk about DataAnnotations later in the tutorial.

Tocar em Criar faz com que o formulário seja enviado para o servidor, no qual as informações do filme são salvas em um banco de dados.Tapping Create causes the form to be posted to the server, where the movie information is saved in a database. O aplicativo redireciona para a URL /Movies, em que as informações do filme recém-criadas são exibidas.The app redirects to the /Movies URL, where the newly created movie information is displayed.

Exibição de filme mostrando a listagem de filmes recém-criados

Crie duas mais entradas de filme adicionais.Create a couple more movie entries. Experimente os links Editar, Detalhes e Excluir, que estão todos funcionais.Try the Edit, Details, and Delete links, which are all functional.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });


    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddDbContext<MvcMovieContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("MvcMovieContext")));
}
public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

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

O código realçado acima mostra o contexto de banco de dados do filme que está sendo adicionado ao contêiner Injeção de Dependência (No arquivo Startup.cs).The highlighted code above shows the movie database context being added to the Dependency Injection container (In the Startup.cs file). services.AddDbContext<MvcMovieContext>(options => especifica o banco de dados a ser usado e a cadeia de conexão.services.AddDbContext<MvcMovieContext>(options => specifies the database to use and the connection string. => é um operador lambda.=> is a lambda operator.

Abra o arquivo Controllers/MoviesController.cs e examine o construtor:Open the Controllers/MoviesController.cs file and examine the constructor:

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.The constructor uses Dependency Injection to inject the database context (MvcMovieContext) into the controller. O contexto de banco de dados é usado em cada um dos métodos CRUD no controlador.The database context is used in each of the CRUD methods in the controller.

Modelos fortemente tipados e a palavra-chave @modelStrongly typed models and the @model keyword

Anteriormente neste tutorial, você viu como um controlador pode passar dados ou objetos para uma exibição usando o dicionário ViewData.Earlier in this tutorial, you saw how a controller can pass data or objects to a view using the ViewData dictionary. O dicionário ViewData é um objeto dinâmico que fornece uma maneira conveniente de associação tardia para passar informações para uma exibição.The ViewData dictionary is a dynamic object that provides a convenient late-bound way to pass information to a view.

O MVC também fornece a capacidade de passar objetos de modelo fortemente tipados para uma exibição.MVC also provides the ability to pass strongly typed model objects to a view. Essa abordagem fortemente tipada permite uma melhor verificação em tempo de compilação do código.This strongly typed approach enables better compile-time checking of your code. O mecanismo de scaffolding usou essa abordagem (ou seja, passando um modelo fortemente tipado) com a classe MoviesController e as exibições quando ele criou os métodos e as exibições.The scaffolding mechanism used this approach (that is, passing a strongly typed model) with the MoviesController class and views when it created the methods and views.

Examine o método Details gerado no arquivo Controllers/MoviesController.cs:Examine the generated Details method in the Controllers/MoviesController.cs file:

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

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

    return View(movie);
}

O parâmetro id geralmente é passado como dados de rota.The id parameter is generally passed as route data. Por exemplo, http://localhost:5000/movies/details/1 define:For example http://localhost:5000/movies/details/1 sets:

  • O controlador para o controlador movies (o primeiro segmento de URL).The controller to the movies controller (the first URL segment).
  • A ação para details (o segundo segmento de URL).The action to details (the second URL segment).
  • A ID como 1 (o último segmento de URL).The id to 1 (the last URL segment).

Você também pode passar a id com uma cadeia de consulta da seguinte maneira:You can also pass in the id with a query string as follows:

http://localhost:1234/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.The id parameter is defined as a nullable type (int?) in case an ID value isn't provided.

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.A lambda expression is passed in to FirstOrDefaultAsync to select movie entities that match the route data or query string value.

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

Um expressão lambda é passada para SingleOrDefaultAsync para selecionar as entidades de filmes que correspondem ao valor da cadeia de consulta ou de dados da rota.A lambda expression is passed in to SingleOrDefaultAsync to select movie entities that match the route data or query string value.

var movie = await _context.Movie
    .SingleOrDefaultAsync(m => m.ID == id);

Se for encontrado um filme, uma instância do modelo Movie será passada para a exibição Details:If a movie is found, an instance of the Movie model is passed to the Details view:

return View(movie);

Examine o conteúdo do arquivo Views/Movies/Details.cshtml:Examine the contents of the Views/Movies/Details.cshtml file:

@model MvcMovie.Models.Movie

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

<h2>Details</h2>

<div>
    <h4>Movie</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Title)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Title)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.ReleaseDate)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Genre)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Genre)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Price)
        </dt>
        <dd>
            @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>

Incluindo uma instrução @model na parte superior do arquivo de exibição, você pode especificar o tipo de objeto esperado pela exibição.By including a @model statement at the top of the view file, you can specify the type of object that the view expects. Quando você criou o controlador de filmes, o Visual Studio incluiu automaticamente a seguinte instrução @model na parte superior do arquivo Details.cshtml:When you created the movie controller, Visual Studio automatically included the following @model statement at the top of the Details.cshtml file:

@model MvcMovie.Models.Movie

Esta diretiva @model permite acessar o filme que o controlador passou para a exibição usando um objeto Model fortemente tipado.This @model directive allows you to access the movie that the controller passed to the view by using a Model object that's strongly typed. 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 Model fortemente tipado.For example, in the Details.cshtml view, the code passes each movie field to the DisplayNameFor and DisplayFor HTML Helpers with the strongly typed Model object. Os métodos Create e Edit e as exibições também passam um objeto de modelo Movie.The Create and Edit methods and views also pass a Movie model object.

Examine a exibição Index.cshtml e o método Index no controlador Movies.Examine the Index.cshtml view and the Index method in the Movies controller. Observe como o código cria um objeto List quando ele chama o método View.Notice how the code creates a List object when it calls the View method. O código passa esta lista Movies do método de ação Index para a exibição:The code passes this Movies list from the Index action method to the view:

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

Quando você criou o controlador de filmes, o scaffolding incluiu automaticamente a seguinte instrução @model na parte superior do arquivo Index.cshtml:When you created the movies controller, scaffolding automatically included the following @model statement at the top of the Index.cshtml file:

@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.The @model directive allows you to access the list of movies that the controller passed to the view by using a Model object that's strongly typed. 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:For example, in the Index.cshtml view, the code loops through the movies with a foreach statement over the strongly typed Model object:

@model IEnumerable<MvcMovie.Models.Movie>

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

<h2>Index</h2>

<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.Because the Model object is strongly typed (as an IEnumerable<Movie> object), each item in the loop is typed as Movie. Entre outros benefícios, isso significa que você obtém a verificação em tempo de compilação do código:Among other benefits, this means that you get compile-time checking of the code:

Menu contextual do IntelliSense em um item de Modelo listando as propriedades disponíveis para ID, Preço, Data de Lançamento e Título

Recursos adicionaisAdditional resources