Páginas Razor com o Entity Framework Core no ASP.NET Core – Tutorial 1 de 8Razor Pages with Entity Framework Core in ASP.NET Core - Tutorial 1 of 8

Por Tom Dykstra e Rick AndersonBy Tom Dykstra and Rick Anderson

O aplicativo Web de exemplo Contoso University demonstra como criar um aplicativo Razor Pages do ASP.NET Core usando o EF (Entity Framework) Core.The Contoso University sample web app demonstrates how to create an ASP.NET Core Razor Pages app using Entity Framework (EF) Core.

O aplicativo de exemplo é um site de uma Contoso University fictícia.The sample app is a web site for a fictional Contoso University. Ele inclui funcionalidades como admissão de alunos, criação de cursos e atribuições de instrutor.It includes functionality such as student admission, course creation, and instructor assignments. Esta página é a primeira de uma série de tutoriais que explica como criar o aplicativo de exemplo Contoso University.This page is the first in a series of tutorials that explain how to build the Contoso University sample app.

Baixe ou exiba o aplicativo concluído.Download or view the completed app. Instruções de download.Download instructions.

Pré-requisitosPrerequisites

Visual Studio 2017 versão 15.7.3 ou posterior com as cargas de trabalho a seguir:Visual Studio 2017 version 15.7.3 or later with the following workloads:

  • ASP.NET e desenvolvimento para a WebASP.NET and web development
  • Desenvolvimento entre plataformas do .NET Core.NET Core cross-platform development

Familiaridade com as Páginas do Razor.Familiarity with Razor Pages. Os novos programadores devem concluir a Introdução às Páginas do Razor antes de começar esta série.New programmers should complete Get started with Razor Pages before starting this series.

Solução de problemasTroubleshooting

Caso tenha um problema que não consiga resolver, em geral, você poderá encontrar a solução comparando o código com o projeto concluído.If you run into a problem you can't resolve, you can generally find the solution by comparing your code to the completed project. Uma boa maneira de obter ajuda é postando uma pergunta no StackOverflow.com sobre o ASP.NET Core ou EF Core.A good way to get help is by posting a question to StackOverflow.com for ASP.NET Core or EF Core.

O aplicativo Web Contoso UniversityThe Contoso University web app

O aplicativo criado nesses tutoriais é um site básico de universidade.The app built in these tutorials is a basic university web site.

Os usuários podem exibir e atualizar informações de alunos, cursos e instrutores.Users can view and update student, course, and instructor information. Veja a seguir algumas das telas criadas no tutorial.Here are a few of the screens created in the tutorial.

Página Índice de Alunos

Página Editar Alunos

O estilo de interface do usuário deste site é próximo ao que é gerado pelos modelos internos.The UI style of this site is close to what's generated by the built-in templates. O foco do tutorial é o EF Core com as Páginas do Razor, não a interface do usuário.The tutorial focus is on EF Core with Razor Pages, not the UI.

Criar o aplicativo Web Razor Pages da ContosoUniversityCreate the ContosoUniversity Razor Pages web app

  • No menu Arquivo do Visual Studio, selecione Novo > Projeto.From the Visual Studio File menu, select New > Project.
  • Crie um novo Aplicativo Web ASP.NET Core.Create a new ASP.NET Core Web Application. Nomeie o projeto ContosoUniversity.Name the project ContosoUniversity. É importante nomear o projeto ContosoUniversity para que os namespaces sejam correspondentes quando o código for copiado/colado.It's important to name the project ContosoUniversity so the namespaces match when code is copy/pasted.
  • Selecione ASP.NET Core 2.1 na lista suspensa e selecione Aplicativo Web.Select ASP.NET Core 2.1 in the dropdown, and then select Web Application.

Para ver imagens das etapas anteriores, confira Criar um aplicativo Web do Razor.For images of the preceding steps, see Create a Razor web app. Execute o aplicativo.Run the app.

Configurar o estilo do siteSet up the site style

Algumas alterações configuram o menu do site, o layout e a home page.A few changes set up the site menu, layout, and home page. Atualize Pages/Shared/_Layout.cshtml com as seguintes alterações:Update Pages/Shared/_Layout.cshtml with the following changes:

  • Altere cada ocorrência de "ContosoUniversity" para "Contoso University".Change each occurrence of "ContosoUniversity" to "Contoso University". Há três ocorrências.There are three occurrences.

  • Adicione entradas de menu para Alunos, Cursos, Instrutores e Departamentos e exclua a entrada de menu Contato.Add menu entries for Students, Courses, Instructors, and Departments, and delete the Contact menu entry.

As alterações são realçadas.The changes are highlighted. (Toda a marcação não é exibida.)(All the markup is not displayed.)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] : Contoso University</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
    </environment>
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a asp-page="/Index" class="navbar-brand">Contoso University</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a asp-page="/Index">Home</a></li>
                    <li><a asp-page="/About">About</a></li>
                    <li><a asp-page="/Students/Index">Students</a></li>
                    <li><a asp-page="/Courses/Index">Courses</a></li>
                    <li><a asp-page="/Instructors/Index">Instructors</a></li>
                    <li><a asp-page="/Departments/Index">Departments</a></li>
                </ul>
            </div>
        </div>
    </nav>

    <partial name="_CookieConsentPartial" />

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2018 : Contoso University</p>
        </footer>
    </div>

    @*Remaining markup not shown for brevity.*@

Em Pages/Index.cshtml, substitua o conteúdo do arquivo pelo seguinte código para substituir o texto sobre o ASP.NET e MVC pelo texto sobre este aplicativo:In Pages/Index.cshtml, replace the contents of the file with the following code to replace the text about ASP.NET and MVC with text about this app:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="jumbotron">
    <h1>Contoso University</h1>
</div>
<div class="row">
    <div class="col-md-4">
        <h2>Welcome to Contoso University</h2>
        <p>
            Contoso University is a sample application that
            demonstrates how to use Entity Framework Core in an
            ASP.NET Core Razor Pages web app.
        </p>
    </div>
    <div class="col-md-4">
        <h2>Build it from scratch</h2>
        <p>You can build the application by following the steps in a series of tutorials.</p>
        <p>
            <a class="btn btn-default"
               href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro">
                See the tutorial &raquo;
            </a>
        </p>
    </div>
    <div class="col-md-4">
        <h2>Download it</h2>
        <p>You can download the completed project from GitHub.</p>
        <p>
            <a class="btn btn-default"
               href="https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/data/ef-rp/intro/samples/cu-final">
                See project source code &raquo;
            </a>
        </p>
    </div>
</div>

Criar o modelo de dadosCreate the data model

Crie classes de entidade para o aplicativo Contoso University.Create entity classes for the Contoso University app. Comece com as três seguintes entidades:Start with the following three entities:

Diagrama de Modelo de Dados Course-Enrollment-Student

Há uma relação um-para-muitos entre as entidades Student e Enrollment.There's a one-to-many relationship between Student and Enrollment entities. Há uma relação um-para-muitos entre as entidades Course e Enrollment.There's a one-to-many relationship between Course and Enrollment entities. Um aluno pode se registrar em qualquer quantidade de cursos.A student can enroll in any number of courses. Um curso pode ter qualquer quantidade de alunos registrados.A course can have any number of students enrolled in it.

Nas seções a seguir, é criada uma classe para cada uma dessas entidades.In the following sections, a class for each one of these entities is created.

A entidade StudentThe Student entity

Diagrama da entidade Student

Crie uma pasta Models.Create a Models folder. Na pasta Models, crie um arquivo de classe chamado Student.cs com o seguinte código:In the Models folder, create a class file named Student.cs with the following code:

using System;
using System.Collections.Generic;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

A propriedade ID se torna a coluna de chave primária da tabela de BD (banco de dados) que corresponde a essa classe.The ID property becomes the primary key column of the database (DB) table that corresponds to this class. Por padrão, o EF Core interpreta uma propriedade nomeada ID ou classnameID como a chave primária.By default, EF Core interprets a property that's named ID or classnameID as the primary key. Em classnameID, classname é o nome da classe.In classnameID, classname is the name of the class. A chave primária alternativa reconhecida automaticamente é StudentID no exemplo anterior.The alternative automatically recognized primary key is StudentID in the preceding example.

A propriedade Enrollments é uma propriedade de navegação.The Enrollments property is a navigation property. As propriedades de navegação vinculam-se a outras entidades que estão relacionadas a essa entidade.Navigation properties link to other entities that are related to this entity. Nesse caso, a propriedade Enrollments de uma Student entity armazena todas as entidades Enrollment relacionadas a essa Student.In this case, the Enrollments property of a Student entity holds all of the Enrollment entities that are related to that Student. Por exemplo, se uma linha Aluno no BD tiver duas linhas Registro relacionadas, a propriedade de navegação Enrollments conterá duas entidades Enrollment.For example, if a Student row in the DB has two related Enrollment rows, the Enrollments navigation property contains those two Enrollment entities. Uma linha Enrollment relacionada é uma linha que contém o valor de chave primária do aluno na coluna StudentID.A related Enrollment row is a row that contains that student's primary key value in the StudentID column. Por exemplo, suponha que o aluno com ID=1 tenha duas linhas na tabela Enrollment.For example, suppose the student with ID=1 has two rows in the Enrollment table. A tabela Enrollment tem duas linhas com StudentID = 1.The Enrollment table has two rows with StudentID = 1. StudentID é uma chave estrangeira na tabela Enrollment que especifica o aluno na tabela Student.StudentID is a foreign key in the Enrollment table that specifies the student in the Student table.

Se uma propriedade de navegação puder armazenar várias entidades, a propriedade de navegação deverá ser um tipo de lista, como ICollection<T>.If a navigation property can hold multiple entities, the navigation property must be a list type, such as ICollection<T>. ICollection<T> pode ser especificado ou um tipo como List<T> ou HashSet<T>.ICollection<T> can be specified, or a type such as List<T> or HashSet<T>. Quando ICollection<T> é usado, o EF Core cria uma coleção HashSet<T> por padrão.When ICollection<T> is used, EF Core creates a HashSet<T> collection by default. As propriedades de navegação que armazenam várias entidades são provenientes de relações muitos para muitos e um-para-muitos.Navigation properties that hold multiple entities come from many-to-many and one-to-many relationships.

A entidade EnrollmentThe Enrollment entity

Diagrama da entidade Enrollment

Na pasta Models, crie Enrollment.cs com o seguinte código:In the Models folder, create Enrollment.cs with the following code:

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }
}

A propriedade EnrollmentID é a chave primária.The EnrollmentID property is the primary key. Essa entidade usa o padrão classnameID em vez de ID como a entidade Student.This entity uses the classnameID pattern instead of ID like the Student entity. Normalmente, os desenvolvedores escolhem um padrão e o usam em todo o modelo de dados.Typically developers choose one pattern and use it throughout the data model. Em um tutorial posterior, o uso de uma ID sem nome de classe é mostrado para facilitar a implementação da herança no modelo de dados.In a later tutorial, using ID without classname is shown to make it easier to implement inheritance in the data model.

A propriedade Grade é um enum.The Grade property is an enum. O ponto de interrogação após a declaração de tipo Grade indica que a propriedade Grade permite valor nulo.The question mark after the Grade type declaration indicates that the Grade property is nullable. Uma nota nula é diferente de uma nota zero – nulo significa que uma nota não é conhecida ou que ainda não foi atribuída.A grade that's null is different from a zero grade -- null means a grade isn't known or hasn't been assigned yet.

A propriedade StudentID é uma chave estrangeira e a propriedade de navegação correspondente é Student.The StudentID property is a foreign key, and the corresponding navigation property is Student. Uma entidade Enrollment está associada a uma entidade Student e, portanto, a propriedade contém uma única entidade Student.An Enrollment entity is associated with one Student entity, so the property contains a single Student entity. A entidade Student é distinta da propriedade de navegação Student.Enrollments, que contém várias entidades Enrollment.The Student entity differs from the Student.Enrollments navigation property, which contains multiple Enrollment entities.

A propriedade CourseID é uma chave estrangeira e a propriedade de navegação correspondente é Course.The CourseID property is a foreign key, and the corresponding navigation property is Course. Uma entidade Enrollment está associada a uma entidade Course.An Enrollment entity is associated with one Course entity.

O EF Core interpreta uma propriedade como uma chave estrangeira se ela é nomeada <navigation property name><primary key property name>.EF Core interprets a property as a foreign key if it's named <navigation property name><primary key property name>. Por exemplo, StudentID para a propriedade de navegação Student, pois a chave primária da entidade Student é ID.For example,StudentID for the Student navigation property, since the Student entity's primary key is ID. Propriedades de chave estrangeira também podem ser nomeadas <primary key property name>.Foreign key properties can also be named <primary key property name>. Por exemplo, CourseID, pois a chave primária da entidade Course é CourseID.For example, CourseID since the Course entity's primary key is CourseID.

A entidade CourseThe Course entity

Diagrama de entidade Curso

Na pasta Models, crie Course.cs com o seguinte código:In the Models folder, create Course.cs with the following code:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

A propriedade Enrollments é uma propriedade de navegação.The Enrollments property is a navigation property. Uma entidade Course pode estar relacionada a qualquer quantidade de entidades Enrollment.A Course entity can be related to any number of Enrollment entities.

O atributo DatabaseGenerated permite que o aplicativo especifique a chave primária em vez de fazer com que ela seja gerada pelo BD.The DatabaseGenerated attribute allows the app to specify the primary key rather than having the DB generate it.

Gere um modelo de aluno por scaffoldScaffold the student model

Nesta seção, é feito o scaffold do modelo de aluno.In this section, the student model is scaffolded. Ou seja, a ferramenta de scaffolding gera páginas para operações de CRUD (Criar, Ler, Atualizar e Excluir) para o modelo de aluno.That is, the scaffolding tool produces pages for Create, Read, Update, and Delete (CRUD) operations for the student model.

  • Compile o projeto.Build the project.
  • Crie a pasta Pages/Students.Create the Pages/Students folder.
  • No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Pages/Students > Adicionar > Novo Item com Scaffold.In Solution Explorer, right click on the Pages/Students folder > Add > New Scaffolded Item.
  • Na caixa de diálogo Adicionar Scaffold, selecione Razor Pages usando o Entity Framework (CRUD) > Adicionar.In the Add Scaffold dialog, select Razor Pages using Entity Framework (CRUD) > ADD.

Conclua a caixa de diálogo Adicionar Razor Pages usando o Entity Framework (CRUD):Complete the Add Razor Pages using Entity Framework (CRUD) dialog:

  • Na lista suspensa classe Modelo, selecione Aluno (ContosoUniversity.Models).In the Model class drop-down, select Student (ContosoUniversity.Models).
  • Na linha Classe de contexto de dados, selecione o sinal de (mais) + e altere o nome gerado para ContosoUniversity.Models.SchoolContext.In the Data context class row, select the + (plus) sign and change the generated name to ContosoUniversity.Models.SchoolContext.
  • Na lista suspensa Classe de contexto de dados, selecione ContosoUniversity.Models.SchoolContextIn the Data context class drop-down, select ContosoUniversity.Models.SchoolContext
  • Selecione Adicionar.Select Add.

Caixa de diálogo CRUD

Confira Fazer scaffold do modelo de filme se tiver problemas na etapa anterior.See Scaffold the movie model if you have a problem with the preceding step.

O processo de scaffold criou e alterou os seguintes arquivos:The scaffold process created and changed the following files:

Arquivos criadosFiles created

  • Pages/Students Criar, Excluir, Detalhes, Editar, Índice.Pages/Students Create, Delete, Details, Edit, Index.
  • Data/SchoolContext.csData/SchoolContext.cs

Atualizações de arquivoFile updates

  • Startup.cs: alterações a esse arquivo serão detalhadas na próxima seção.Startup.cs : Changes to this file are detailed in the next section.
  • appsettings.json: a cadeia de conexão usada para se conectar a um banco de dados local é adicionada.appsettings.json : The connection string used to connect to a local database is added.

Examinar o contexto registrado com a injeção de dependênciaExamine the context registered with dependency injection

O ASP.NET Core é construído com a injeção de dependência.ASP.NET Core is built with dependency injection. Serviços (como o contexto de BD do EF Core) são registrados com injeção de dependência durante a inicialização do aplicativo.Services (such as the EF Core DB context) are registered with dependency injection during application startup. Os componentes que exigem esses serviços (como as Páginas do Razor) recebem esses serviços por meio de parâmetros do construtor.Components that require these services (such as Razor Pages) are provided these services via constructor parameters. O código de construtor que obtém uma instância de contexto do BD é mostrado mais adiante no tutorial.The constructor code that gets a db context instance is shown later in the tutorial.

A ferramenta de scaffolding criou automaticamente um contexto de BD e o registrou no contêiner da injeção de dependência.The scaffolding tool automatically created a DB Context and registered it with the dependency injection container.

Examine o método ConfigureServices em Startup.cs.Examine the ConfigureServices method in Startup.cs. A linha destacada foi adicionada pelo scaffolder:The highlighted line was added by the scaffolder:

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<SchoolContext>(options =>
       options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
}

O nome da cadeia de conexão é passado para o contexto com a chamada de um método em um objeto DbContextOptions.The name of the connection string is passed in to the context by calling a method on a DbContextOptions object. Para o desenvolvimento local, o sistema de configuração do ASP.NET Core lê a cadeia de conexão do arquivo appsettings.json.For local development, the ASP.NET Core configuration system reads the connection string from the appsettings.json file.

Atualizar o principalUpdate main

Em Program.cs, modifique o método Main para fazer o seguinte:In Program.cs, modify the Main method to do the following:

  • Obtenha uma instância de contexto de BD do contêiner de injeção de dependência.Get a DB context instance from the dependency injection container.
  • Chame o EnsureCreated.Call the EnsureCreated.
  • Descarte o contexto quando o método EnsureCreated for concluído.Dispose the context when the EnsureCreated method completes.

O código a seguir mostra o arquivo Program.cs atualizado.The following code shows the updated Program.cs file.

using ContosoUniversity.Models;                   // SchoolContext
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;   // CreateScope
using Microsoft.Extensions.Logging;
using System;

namespace ContosoUniversity
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    context.Database.EnsureCreated();
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }

            host.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

EnsureCreated garante que o banco de dados do contexto exista.EnsureCreated ensures that the database for the context exists. Se ele existir, nenhuma ação será realizada.If it exists, no action is taken. Se ele não existir, o banco de dados e todos os seus esquemas serão criados.If it does not exist, then the database and all its schema are created. EnsureCreated não usa migrações para criar o banco de dados.EnsureCreated does not use migrations to create the database. Um banco de dados criado com EnsureCreated não pode ser atualizado posteriormente usando migrações.A database that is created with EnsureCreated cannot be later updated using migrations.

EnsureCreated é chamado na inicialização do aplicativo, que permite que o seguinte fluxo de trabalho:EnsureCreated is called on app start, which allows the following work flow:

  • Exclua o BD.Delete the DB.
  • Altere o esquema de BD (por exemplo, adicione um campo EmailAddress).Change the DB schema (for example, add an EmailAddress field).
  • Execute o aplicativo.Run the app.
  • EnsureCreated cria um BD com a coluna EmailAddress.EnsureCreated creates a DB with theEmailAddress column.

EnsureCreated é conveniente no início do desenvolvimento quando o esquema está evoluindo rapidamente.EnsureCreated is convenient early in development when the schema is rapidly evolving. Mais tarde, no tutorial do banco de dados, é excluído e as migrações são usadas.Later in the tutorial the DB is deleted and migrations are used.

Testar o aplicativoTest the app

Execute o aplicativo e aceite a política de cookies.Run the app and accept the cookie policy. Este aplicativo não armazena informações pessoais.This app doesn't keep personal information. Você pode ler sobre a política de cookies em Suporte para a RGPD (Regulamento Geral sobre a Proteção de Dados) da UE.You can read about the cookie policy at EU General Data Protection Regulation (GDPR) support.

  • Selecione o link Alunos e Criar Novo.Select the Students link and then Create New.
  • Teste os links Editar, Detalhes e Excluir.Test the Edit, Details, and Delete links.

Examine o contexto de BD SchoolContextExamine the SchoolContext DB context

A classe principal que coordena a funcionalidade do EF Core de um modelo de dados é a classe de contexto de BD.The main class that coordinates EF Core functionality for a given data model is the DB context class. O contexto de dados deriva de Microsoft.EntityFrameworkCore.DbContext.The data context is derived from Microsoft.EntityFrameworkCore.DbContext. O contexto de dados especifica quais entidades são incluídas no modelo de dados.The data context specifies which entities are included in the data model. Neste projeto, a classe é chamada SchoolContext.In this project, the class is named SchoolContext.

Atualize SchoolContext.cs com o seguinte código:Update SchoolContext.cs with the following code:

using Microsoft.EntityFrameworkCore;

namespace ContosoUniversity.Models
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options)
            : base(options)
        {
        }

        public DbSet<Student> Student { get; set; }
        public DbSet<Enrollment> Enrollment { get; set; }
        public DbSet<Course> Course { get; set; }
    }
}

O código destacado cria uma propriedade DbSet<TEntity> para cada conjunto de entidades.The highlighted code creates a DbSet<TEntity> property for each entity set. Na terminologia do EF Core:In EF Core terminology:

  • Um conjunto de entidades normalmente corresponde a uma tabela de BD.An entity set typically corresponds to a DB table.
  • Uma entidade corresponde a uma linha da tabela.An entity corresponds to a row in the table.

DbSet<Enrollment> e DbSet<Course> podem ser omitidos.DbSet<Enrollment> and DbSet<Course> could be omitted. O EF Core inclui-os de forma implícita porque a entidade Student referencia a entidade Enrollment e a entidade Enrollment referencia a entidade Course.EF Core includes them implicitly because the Student entity references the Enrollment entity, and the Enrollment entity references the Course entity. Para este tutorial, mantenha DbSet<Enrollment> e DbSet<Course> no SchoolContext.For this tutorial, keep DbSet<Enrollment> and DbSet<Course> in the SchoolContext.

SQL Server Express LocalDBSQL Server Express LocalDB

A cadeia de conexão especifica um LocalDB do SQL Server.The connection string specifies SQL Server LocalDB. LocalDB é uma versão leve do Mecanismo de Banco de Dados do SQL Server Express destinado ao desenvolvimento de aplicativos, e não ao uso em produção.LocalDB is a lightweight version of the SQL Server Express Database Engine and is intended for app development, not production use. O LocalDB é iniciado sob demanda e executado no modo de usuário e, portanto, não há nenhuma configuração complexa.LocalDB starts on demand and runs in user mode, so there's no complex configuration. Por padrão, o LocalDB cria arquivos .mdf de BD no diretório C:/Users/<user>.By default, LocalDB creates .mdf DB files in the C:/Users/<user> directory.

Adicionar um código para inicializar o BD com os dados de testeAdd code to initialize the DB with test data

O EF Core cria um BD vazio.EF Core creates an empty DB. Nesta seção, um método Initialize é escrito para populá-lo com os dados de teste.In this section, an Initialize method is written to populate it with test data.

Na pasta Dados, crie um novo arquivo de classe chamado DbInitializer.cs e adicione o seguinte código:In the Data folder, create a new class file named DbInitializer.cs and add the following code:

using ContosoUniversity.Models;
using System;
using System.Linq;

namespace ContosoUniversity.Models
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            // context.Database.EnsureCreated();

            // Look for any students.
            if (context.Student.Any())
            {
                return;   // DB has been seeded
            }

            var students = new Student[]
            {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
            new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
            new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
            };
            foreach (Student s in students)
            {
                context.Student.Add(s);
            }
            context.SaveChanges();

            var courses = new Course[]
            {
            new Course{CourseID=1050,Title="Chemistry",Credits=3},
            new Course{CourseID=4022,Title="Microeconomics",Credits=3},
            new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
            new Course{CourseID=1045,Title="Calculus",Credits=4},
            new Course{CourseID=3141,Title="Trigonometry",Credits=4},
            new Course{CourseID=2021,Title="Composition",Credits=3},
            new Course{CourseID=2042,Title="Literature",Credits=4}
            };
            foreach (Course c in courses)
            {
                context.Course.Add(c);
            }
            context.SaveChanges();

            var enrollments = new Enrollment[]
            {
            new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
            new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
            new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
            new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
            new Enrollment{StudentID=3,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
            new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
            new Enrollment{StudentID=6,CourseID=1045},
            new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
            };
            foreach (Enrollment e in enrollments)
            {
                context.Enrollment.Add(e);
            }
            context.SaveChanges();
        }
    }
}

Observação: O código anterior usa Models para o namespace (namespace ContosoUniversity.Models) em vez de Data.Note: The preceding code uses Models for the namespace (namespace ContosoUniversity.Models) rather than Data. Models é consistente com o código gerado pelo scaffolder.Models is consistent with the scaffolder-generated code. Para saber mais, confira este problema de scaffolding do GitHub.For more information, see this GitHub scaffolding issue.

O código verifica se há alunos no BD.The code checks if there are any students in the DB. Se não houver nenhum aluno no BD, o BD será inicializado com os dados de teste.If there are no students in the DB, the DB is initialized with test data. Ele carrega os dados de teste em matrizes em vez de em coleções List<T> para otimizar o desempenho.It loads test data into arrays rather than List<T> collections to optimize performance.

O método EnsureCreated cria o BD automaticamente para o contexto de BD.The EnsureCreated method automatically creates the DB for the DB context. Se o BD existir, EnsureCreated retornará sem modificar o BD.If the DB exists, EnsureCreated returns without modifying the DB.

Em Program.cs, modifique o método Main para chamar Initialize:In Program.cs, modify the Main method to call Initialize:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();

        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;

            try
            {
                var context = services.GetRequiredService<SchoolContext>();
                // using ContosoUniversity.Data; 
                DbInitializer.Initialize(context);
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred creating the DB.");
            }
        }

        host.Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

Exclua todos os registros de alunos e reinicie o aplicativo.Delete any student records and restart the app. Se o BD não for inicializado, defina um ponto de interrupção em Initialize para diagnosticar o problema.If the DB is not initialized, set a break point in Initialize to diagnose the problem.

Exibir o BDView the DB

O nome do banco de dados é gerado usando o nome do contexto fornecido anteriormente, além de um traço e um GUID.The database name is generated from the context name you provided earlier plus a dash and a GUID. Assim, o nome do banco de dados será "SchoolContext-{GUID}".Thus, the database name will be "SchoolContext-{GUID}". O GUID será diferente para cada usuário.The GUID will be different for each user. Abra o SSOX (Pesquisador de Objetos do SQL Server) no menu Exibir do Visual Studio.Open SQL Server Object Explorer (SSOX) from the View menu in Visual Studio. No SSOX, clique em (localdb)\MSSQLLocalDB > Bancos de Dados > SchoolContext-{GUID}.In SSOX, click (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}.

Expanda o nó Tabelas.Expand the Tables node.

Clique com o botão direito do mouse na tabela Aluno e clique em Exibir Dados para ver as colunas criadas e as linhas inseridas na tabela.Right-click the Student table and click View Data to see the columns created and the rows inserted into the table.

Código assíncronoAsynchronous code

A programação assíncrona é o modo padrão do ASP.NET Core e EF Core.Asynchronous programming is the default mode for ASP.NET Core and EF Core.

Um servidor Web tem um número limitado de threads disponíveis e, em situações de alta carga, todos os threads disponíveis podem estar em uso.A web server has a limited number of threads available, and in high load situations all of the available threads might be in use. Quando isso acontece, o servidor não pode processar novas solicitações até que os threads são liberados.When that happens, the server can't process new requests until the threads are freed up. Com um código síncrono, muitos threads podem ser vinculados enquanto realmente não são fazendo nenhum trabalho porque estão aguardando a conclusão da E/S.With synchronous code, many threads may be tied up while they aren't actually doing any work because they're waiting for I/O to complete. Com um código assíncrono, quando um processo está aguardando a conclusão da E/S, seu thread é liberado para o servidor para ser usado para processar outras solicitações.With asynchronous code, when a process is waiting for I/O to complete, its thread is freed up for the server to use for processing other requests. Como resultado, o código assíncrono permite que os recursos do servidor sejam usados com mais eficiência, e o servidor fica capacitado a manipular mais tráfego sem atrasos.As a result, asynchronous code enables server resources to be used more efficiently, and the server is enabled to handle more traffic without delays.

O código assíncrono introduz uma pequena quantidade de sobrecarga em tempo de execução.Asynchronous code does introduce a small amount of overhead at run time. Para situações de baixo tráfego, o impacto no desempenho é insignificante, enquanto para situações de alto tráfego, a melhoria de desempenho potencial é significativa.For low traffic situations, the performance hit is negligible, while for high traffic situations, the potential performance improvement is substantial.

No código a seguir, a palavra-chave async, o valor retornado Task<T>, a palavra-chave await e o método ToListAsync fazem o código ser executado de forma assíncrona.In the following code, the async keyword, Task<T> return value, await keyword, and ToListAsync method make the code execute asynchronously.

public async Task OnGetAsync()
{
    Student = await _context.Student.ToListAsync();
}
  • A palavra-chave async instrui o compilador a:The async keyword tells the compiler to:

    • Gerar retornos de chamada para partes do corpo do método.Generate callbacks for parts of the method body.
    • Criar automaticamente o objeto Task que é retornado.Automatically create the Task object that's returned. Para obter mais informações, consulte Tipo de retorno de Tarefa.For more information, see Task Return Type.
  • O tipo de retorno implícito Task representa um trabalho em andamento.The implicit return type Task represents ongoing work.

  • A palavra-chave await faz com que o compilador divida o método em duas partes.The await keyword causes the compiler to split the method into two parts. A primeira parte termina com a operação que é iniciada de forma assíncrona.The first part ends with the operation that's started asynchronously. A segunda parte é colocada em um método de retorno de chamada que é chamado quando a operação é concluída.The second part is put into a callback method that's called when the operation completes.

  • ToListAsync é a versão assíncrona do método de extensão ToList.ToListAsync is the asynchronous version of the ToList extension method.

Algumas coisas a serem consideradas ao escrever um código assíncrono que usa o EF Core:Some things to be aware of when writing asynchronous code that uses EF Core:

  • Somente instruções que fazem com que consultas ou comandos sejam enviados ao BD são executadas de forma assíncrona.Only statements that cause queries or commands to be sent to the DB are executed asynchronously. Isso inclui ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync e SaveChangesAsync.That includes, ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync, and SaveChangesAsync. Isso não inclui instruções que apenas alteram um IQueryable, como var students = context.Students.Where(s => s.LastName == "Davolio").It doesn't include statements that just change an IQueryable, such as var students = context.Students.Where(s => s.LastName == "Davolio").
  • Um contexto do EF Core não é thread-safe: não tente realizar várias operações em paralelo.An EF Core context isn't thread safe: don't try to do multiple operations in parallel.
  • Para aproveitar os benefícios de desempenho do código assíncrono, verifique se os pacotes de biblioteca (como para paginação) usam o código assíncrono se eles chamam métodos do EF Core que enviam consultas ao BD.To take advantage of the performance benefits of async code, verify that library packages (such as for paging) use async if they call EF Core methods that send queries to the DB.

Para obter mais informações sobre a programação assíncrona, consulte Visão geral de Async e Programação assíncrona com async e await.For more information about asynchronous programming in .NET, see Async Overview and Asynchronous programming with async and await.

No próximo tutorial, as operações CRUD (criar, ler, atualizar e excluir) básicas são examinadas.In the next tutorial, basic CRUD (create, read, update, delete) operations are examined.

Recursos adicionaisAdditional resources