Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Note
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 10 deste artigo.
Warning
Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e do .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.
Por Tom Dykstra, Jeremy Likness e Jon P Smith
Este é o primeiro de uma série de tutoriais que mostram como usar o Entity Framework (EF) Core em um aplicativo ASP.NET Core Razor Pages . Os tutoriais criam um site para uma Universidade Contoso fictícia. O site inclui funcionalidades como admissão de alunos, criação de cursos e tarefas de instrutores. O tutorial utiliza a abordagem code first, que prioriza o código. Para obter informações sobre como seguir este tutorial usando a primeira abordagem do banco de dados, consulte este problema do Github.
Transfira ou veja a aplicação concluída.Instruções para download.
Prerequisites
- Se você é novo no Razor Pages, consulte a série de tutoriais Introdução ao Razor Pages antes de iniciar esta.
Visual Studio 2022 com a carga de trabalho de ASP.NET e desenvolvimento web .
Mecanismos de banco de dados
As instruções do Visual Studio usam SQL Server LocalDB, uma versão do SQL Server Express que é executada somente no Windows.
Troubleshooting
Se você encontrar um problema que não pode resolver, compare seu código com o projeto concluído. Uma boa maneira de obter ajuda é postando uma pergunta para StackOverflow.com, usando a tag ASP.NET Core ou a EF Core tag .
O aplicativo de exemplo
O aplicativo construído nesses tutoriais é um site básico da universidade. Os usuários podem visualizar e atualizar informações de alunos, cursos e instrutores. Aqui estão algumas das telas criadas no tutorial.
Página 
O estilo da interface do usuário deste site é baseado nos modelos de projeto internos. O foco do tutorial está em como usar EF Core com o ASP.NET Core, não em como personalizar a interface do usuário.
Opcional: criar o download de exemplo
Esta etapa é opcional. A criação do aplicativo concluído é recomendada quando você tem problemas que não consegue resolver. Se você encontrar um problema que não pode resolver, compare seu código com o projeto concluído. Instruções para download.
Selecione ContosoUniversity.csproj para abrir o projeto.
Construa o projeto.
No Console do Gerenciador de Pacotes (PMC), execute o seguinte comando:
Update-Database
Execute o projeto para semear o banco de dados.
Criar o projeto de aplicativo Web
Inicie o Visual Studio 2022 e selecione Criar um novo projeto.
Na caixa de diálogo Criar um novo projeto
, selecione ASP.NET Core Web App e, em seguida, selecioneSeguinte .
Na caixa de diálogo Configurar o novo projeto, digite
ContosoUniversitypara nome do projeto. É importante nomear o projeto ContosoUniversity, incluindo a capitalização correspondente, para que os namespaces correspondam quando se copiar e colar código de exemplo.Selecione Avançar.
Na caixa de diálogo Informações adicionais, selecione .NET 6.0 (Suporte de longo prazo) e, em seguida, selecione Criar.
Configurar o estilo do site
Copie e cole o seguinte código no Pages/Shared/_Layout.cshtml arquivo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/ContosoUniversity.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2021 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
O arquivo de layout define o cabeçalho, o rodapé e o menu do site. O código anterior faz as seguintes alterações:
- Substitua cada ocorrência de "ContosoUniversity" por "Contoso University". Há três ocorrências.
- As entradas de menu Home e Privacy são eliminadas.
- As inscrições são adicionadas para Sobre, Alunos, Cursos, Instrutores e Departamentos.
No Pages/Index.cshtml, substitua o conteúdo do arquivo pelo seguinte código:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="row mb-auto">
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 mb-4 ">
<p class="card-text">
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>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column position-static">
<p class="card-text mb-auto">
You can build the application by following the steps in a series of tutorials.
</p>
<p>
@* <a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
*@ </p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column">
<p class="card-text mb-auto">
You can download the completed project from GitHub.
</p>
<p>
@* <a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
*@ </p>
</div>
</div>
</div>
</div>
O código anterior substitui o texto sobre ASP.NET Core por texto sobre este aplicativo.
Execute o aplicativo para verificar se a página inicial aparece.
O modelo de dados
As seções a seguir criam um modelo de dados:
Um aluno pode se inscrever em qualquer número de cursos, e um curso pode ter qualquer número de alunos matriculados nele.
A entidade estudantil
- Crie uma pasta Modelos na pasta do projeto.
- Crie
Models/Student.cscom o seguinte código: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 ID propriedade se torna a coluna de chave primária da tabela de banco de dados que corresponde a essa classe. Por padrão, EF Core interpreta uma propriedade nomeada ID ou classnameID como a chave primária. Portanto, o nome alternativo reconhecido automaticamente para a chave primária da Student classe é StudentID. Para mais informações, consulte EF Core - Chaves.
A propriedade Enrollments é uma propriedade de navegação . As propriedades de navegação mantêm outras entidades que estão associadas a esta entidade. Neste caso, a Enrollments propriedade de uma Student entidade detém todas as Enrollment entidades que estão relacionadas com esse Aluno. Por exemplo, se uma linha Estudante no banco de dados tiver duas linhas de Inscrição relacionadas, a Enrollments propriedade de navegação conterá essas duas entidades de Inscrição.
No banco de dados, uma linha Inscrição estará relacionada a uma linha Aluno se sua StudentID coluna contiver o valor de ID do aluno. Por exemplo, suponha que uma linha Student tenha ID=1. As linhas de inscrição relacionadas terão StudentID = 1.
StudentID é uma chave estrangeira na tabela Inscrição.
A Enrollments propriedade é definida como ICollection<Enrollment> porque pode haver várias entidades de Registro relacionadas. Outros tipos de coleção podem ser usados, como List<Enrollment> ou HashSet<Enrollment>. Quando ICollection<Enrollment> é usado, EF Core cria uma HashSet<Enrollment> coleção por padrão.
A entidade de Inscrição
Crie Models/Enrollment.cs com o seguinte código:
using System.ComponentModel.DataAnnotations;
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; }
[DisplayFormat(NullDisplayText = "No grade")]
public Grade? Grade { get; set; }
public Course Course { get; set; }
public Student Student { get; set; }
}
}
A EnrollmentID propriedade é a chave primária, esta entidade usa o classnameID padrão em vez de ID por si só. Para um modelo de dados de produção, muitos desenvolvedores escolhem um padrão e o usam de forma consistente. Este tutorial usa ambos apenas para ilustrar que ambos funcionam. O uso ID sem classname facilita a implementação de alguns tipos de alterações no modelo de dados.
A propriedade Grade é um enum. O ponto de interrogação após a declaração de Grade tipo indica que a Grade propriedade é anulável. Uma nota nula é diferente de uma nota zero — nula significa que uma nota não é conhecida ou ainda não foi atribuída.
A propriedade StudentID é uma chave estrangeira e a propriedade de navegação correspondente é Student. Uma Enrollment entidade está associada a uma Student entidade, portanto, a propriedade contém uma única Student entidade.
A propriedade CourseID é uma chave estrangeira e a propriedade de navegação correspondente é Course. Uma entidade Enrollment está associada a uma entidade Course.
EF Core interpreta uma propriedade como uma chave estrangeira se ela for nomeada <navigation property name><primary key property name>. Por exemplo,StudentID é a chave estrangeira para Student propriedade de navegação, visto que a chave primária da entidade Student é ID. As propriedades da chave estrangeira também podem ser nomeadas <primary key property name>. Por exemplo, CourseID desde que a Course chave primária da entidade seja CourseID.
A entidade do Curso
Crie Models/Course.cs com o seguinte código:
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. Uma entidade Course pode estar relacionada com qualquer número de entidades Enrollment.
O DatabaseGenerated atributo permite que o aplicativo especifique a chave primária em vez de fazer com que o banco de dados a gere.
Crie o aplicativo. O compilador gera vários avisos sobre como null valores são tratados. Consulte este problema do GitHub, Tipos de referência anuláveis e Tutorial: Expresse sua intenção de design mais claramente com tipos de referência anuláveis e não anuláveis para obter mais informações.
Para eliminar os avisos de tipos de referência anuláveis, remova a seguinte linha do arquivo ContosoUniversity.csproj:
<Nullable>enable</Nullable>
O motor de andaimes atualmente não suporta tipos de referência anuláveis, portanto, os modelos usados em andaimes também não podem.
Remova a anotação de tipo de referência anulável de ? em public string? RequestId { get; set; } para que o projeto seja compilado sem avisos do compilador.
Páginas de apoio ao estudante
Nesta seção, a ferramenta de andaime ASP.NET Core é usada para gerar:
- Uma EF Core
DbContextaula. O contexto é a classe principal que coordena a funcionalidade do Entity Framework para um determinado modelo de dados. Deriva da Microsoft.EntityFrameworkCore.DbContext classe. -
Razor páginas que executam operações de Criar, Ler, Atualizar e Excluir (CRUD) para entidade
Student.
- Crie uma pasta Páginas/Alunos .
- No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Páginas/Alunos e selecione Adicionar>Novo Item de Andaime.
- Na caixa de diálogo Adicionar Novo Item de Andaime :
- Na guia à esquerda, selecione Páginas comuns >> instaladas Razor
- Selecione Razor Páginas usando o Entity Framework (CRUD)>ADD.
- Na caixa de diálogo Adicionar Razor páginas usando o Entity Framework (CRUD):
- Na lista suspensa Classe modelo, selecione Estudante (ContosoUniversity.Models).
- Na linha da classe de contexto de dados, selecione o sinal de + (mais).
- Altere o nome do contexto de dados para terminar em
SchoolContextvez deContosoUniversityContext. O nome de contexto atualizado:ContosoUniversity.Data.SchoolContext - Selecione Adicionar para concluir a adição da classe de contexto de dados.
- Selecione Adicionar para concluir a caixa de diálogo Adicionar Razor páginas .
- Altere o nome do contexto de dados para terminar em
Os seguintes pacotes são instalados automaticamente:
Microsoft.EntityFrameworkCore.SqlServerMicrosoft.EntityFrameworkCore.ToolsMicrosoft.VisualStudio.Web.CodeGeneration.Design
Se a etapa anterior falhar, construa o projeto e tente novamente a etapa do andaime.
O processo de andaime:
- Cria Razor páginas na pasta Páginas/Alunos :
-
Create.cshtmleCreate.cshtml.cs -
Delete.cshtmleDelete.cshtml.cs -
Details.cshtmleDetails.cshtml.cs -
Edit.cshtmleEdit.cshtml.cs -
Index.cshtmleIndex.cshtml.cs
-
- Cria
Data/SchoolContext.cs. - Adiciona o contexto à injeção de dependência no
Program.cs. - Adiciona uma cadeia de conexão de banco de dados ao
appsettings.json.
Cadeia de conexão de banco de dados
A ferramenta de andaime gera uma cadeia de conexão no appsettings.json arquivo.
A cadeia de conexão especifica o SQL Server LocalDB:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=SchoolContext-0e9;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
O LocalDB é uma versão leve do Mecanismo de Banco de Dados do SQL Server Express e destina-se ao desenvolvimento de aplicativos, não ao uso em produção. Por padrão, o LocalDB cria .mdf arquivos no C:/Users/<user> diretório.
Atualizar a classe de contexto do banco de dados
A classe principal que coordena a EF Core funcionalidade para um determinado modelo de dados é a classe de contexto do banco de dados. O contexto é derivado de Microsoft.EntityFrameworkCore.DbContext. O contexto especifica quais entidades são incluídas no modelo de dados. Neste projeto, a classe é chamada SchoolContext.
Atualize Data/SchoolContext.cs com o seguinte código:
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext (DbContextOptions<SchoolContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
O código anterior muda do singular DbSet<Student> Student para o plural DbSet<Student> Students. Para fazer com que o código das Razor Páginas corresponda ao novo DBSet nome, faça uma alteração global a partir de:
_context.Student. Para: _context.Students.
São 8 ocorrências.
Como um conjunto de entidades contém várias entidades, muitos desenvolvedores preferem que os nomes de propriedade DBSet sejam plurais.
O código destacado:
- Cria uma DbSet<TEntity> propriedade para cada conjunto de entidades. Na EF Core terminologia:
- Um conjunto de entidades normalmente corresponde a uma tabela de banco de dados.
- Uma entidade corresponde a uma linha na tabela.
- Chamadas OnModelCreating.
OnModelCreating:- É chamado quando
SchoolContextfoi inicializado, mas antes que o modelo tenha sido protegido e usado para inicializar o contexto. - É obrigatório porque posteriormente no tutorial a
Studententidade terá referências às outras entidades.
- É chamado quando
Esperamos corrigir esse problema em uma versão futura.
Program.cs
ASP.NET Core é construído com injeção de dependência. Serviços como o SchoolContext são registados com injeção de dependência durante a inicialização da aplicação. Os componentes que requerem esses serviços, como as Razor páginas, têm esses serviços disponibilizados através de parâmetros do construtor. O código do construtor que obtém uma instância de contexto de banco de dados é mostrado posteriormente no tutorial.
A ferramenta de andaime registrou automaticamente a classe de contexto com o contêiner de injeção de dependência.
O andaime adicionou as seguintes linhas destacadas:
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext")));
O nome da cadeia de conexão é passado para o contexto chamando um método em um objeto DbContextOptions. Para o desenvolvimento local, o sistema de configuração ASP.NET Core lê a cadeia de conexão do arquivo appsettings.json ou do arquivo appsettings.Development.json.
Adicionar o filtro de exceção do banco de dados
Adicionar AddDatabaseDeveloperPageExceptionFilter e UseMigrationsEndPoint como mostrado no código a seguir:
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext")));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
else
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
Adicione o pacote NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.
No Console do Gerenciador de Pacotes, digite o seguinte para adicionar o pacote NuGet:
Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
O Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore pacote NuGet fornece middleware ASP.NET Core para páginas de erro do Entity Framework Core. Esse middleware ajuda a detetar e diagnosticar erros com migrações do Entity Framework Core.
O AddDatabaseDeveloperPageExceptionFilter fornece informações úteis sobre erros no ambiente de desenvolvimento para erros de migrações do Entity Framework.
Criar a base de dados
Atualize Program.cs para criar o banco de dados se ele não existir:
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("SchoolContext")));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
else
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
// DbInitializer.Initialize(context);
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
O EnsureCreated método não executa nenhuma ação se existir um banco de dados para o contexto. Se nenhum banco de dados existir, ele criará o banco de dados e o esquema.
EnsureCreated Permite o seguinte fluxo de trabalho para lidar com alterações de modelo de dados:
- Exclua o banco de dados. Todos os dados existentes são perdidos.
- Altere o modelo de dados. Por exemplo, adicione um
EmailAddresscampo. - Execute o aplicativo.
-
EnsureCreatedCria um banco de dados com o novo esquema.
Esse fluxo de trabalho funciona no início do desenvolvimento, quando o esquema está evoluindo rapidamente, desde que os dados não precisem ser preservados. A situação é diferente quando os dados introduzidos na base de dados têm de ser preservados. Quando for esse o caso, use migrações.
Mais tarde na série de tutoriais, o banco de dados criado por EnsureCreated é excluído e utilizam-se migrações. Um banco de dados criado por EnsureCreated não pode ser atualizado usando migrações.
Testar a aplicação
- Execute o aplicativo.
- Selecione o link Alunos e, em seguida, Criar novo.
- Teste os links Editar, Detalhes e Excluir.
Semear o banco de dados
O EnsureCreated método cria um banco de dados vazio. Esta seção adiciona código que preenche o banco de dados com dados de teste.
Crie Data/DbInitializer.cs com o seguinte código:
using ContosoUniversity.Models;
namespace ContosoUniversity.Data
{
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
// Look for any students.
if (context.Students.Any())
{
return; // DB has been seeded
}
var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
};
context.Students.AddRange(students);
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}
};
context.Courses.AddRange(courses);
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},
};
context.Enrollments.AddRange(enrollments);
context.SaveChanges();
}
}
}
O código verifica se há algum aluno no banco de dados. Se não houver alunos, adiciona dados de teste ao banco de dados. Ele cria os dados de teste em matrizes em vez de List<T> coleções para otimizar o desempenho.
- No
Program.cs, remova//daDbInitializer.Initializelinha:
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
DbInitializer.Initialize(context);
}
Pare o aplicativo se ele estiver em execução e execute o seguinte comando no Console do Gerenciador de Pacotes (PMC):
Drop-Database -ConfirmResponda com
Ypara excluir o banco de dados.
- Reinicie o aplicativo.
- Selecione a página Alunos para ver os dados pré-definidos.
Ver a base de dados
- Abra o Pesquisador de Objetos do SQL Server (SSOX) no menu Exibir no Visual Studio.
- Em SSOX, selecione (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. O nome do banco de dados é gerado a partir do nome de contexto fornecido anteriormente, além de um traço e um GUID.
- Expanda o nó Tabelas .
- 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.
- Clique com o botão direito do rato na tabela Student e clique em Ver Código para ver como o modelo se mapeia
Studentpara o esquema daStudenttabela.
Métodos EF assíncronos em aplicativos Web ASP.NET Core
A programação assíncrona é o modo padrão para ASP.NET Core e 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. Quando isso acontece, o servidor não pode processar novas solicitações até que os threads sejam liberados. Com o código síncrono, muitos threads podem ficar presos enquanto não estão fazendo trabalho porque estão aguardando a conclusão da E/S. Com o código assíncrono, quando um processo está aguardando a conclusão da E/S, seu thread é liberado para o servidor usar para processar outras solicitações. Como resultado, o código assíncrono permite que os recursos do servidor sejam usados de forma mais eficiente e o servidor pode lidar com mais tráfego sem atrasos.
O código assíncrono introduz uma pequena quantidade de sobrecarga em tempo de execução. Para situações de baixo tráfego, o impacto no desempenho é insignificante, enquanto para situações de tráfego elevado, a melhoria potencial do desempenho é substancial.
No código a seguir, a palavra-chave assíncrona , Task o valor de retorno, await a palavra-chave e ToListAsync o método fazem com que o código seja executado de forma assíncrona.
public async Task OnGetAsync()
{
Students = await _context.Students.ToListAsync();
}
- A
asyncpalavra-chave diz ao compilador para:- Gere callbacks para partes do corpo do método.
- Crie o objeto Task que é retornado.
- O
Tasktipo de retorno representa o trabalho em andamento. - A palavra-chave
awaitfaz com que o compilador divida o método em duas partes. A primeira parte termina com a operação iniciada de forma assíncrona. A segunda parte é usada numa função de retorno que é chamada quando a operação é concluída. -
ToListAsyncé a versão assíncrona do método de extensãoToList.
Algumas coisas a ter em conta ao escrever código assíncrono que utiliza EF Core:
- Somente instruções que fazem com que consultas ou comandos sejam enviados ao banco de dados são executadas de forma assíncrona. Isso inclui
ToListAsync,SingleOrDefaultAsync,FirstOrDefaultAsync, eSaveChangesAsync. Ele não inclui declarações que apenas alteram umIQueryable, comovar students = context.Students.Where(s => s.LastName == "Davolio"). - Um EF Core contexto não é seguro para execução simultânea: não execute várias operações em paralelo.
- Para aproveitar os benefícios de desempenho do código assíncrono, verifique se os pacotes de biblioteca (como para paginação) usam async se chamarem EF Core métodos que enviam consultas para o banco de dados.
Para obter mais informações sobre programação assíncrona no .NET, consulte Visão geral assíncrona e Programação assíncrona com async e await.
Warning
A implementação assíncrona de Microsoft.Data.SqlClient tem alguns problemas conhecidos (#593, #601 e outros). Se você estiver vendo problemas de desempenho inesperados, tente usar a execução de comando de sincronização, especialmente ao lidar com texto grande ou valores binários.
Considerações sobre desempenho
Em geral, uma página da Web não deve carregar um número arbitrário de linhas. Uma consulta deve usar paginação ou uma abordagem limitante. Por exemplo, a consulta anterior pode ser usada Take para limitar as linhas retornadas:
public async Task OnGetAsync()
{
Student = await _context.Students.Take(10).ToListAsync();
}
Enumerar uma tabela extensa numa visualização pode retornar uma resposta HTTP 200 parcialmente construída se uma exceção de base de dados ocorrer a meio do processo de enumeração.
A paginação é abordada mais adiante no tutorial.
Para obter mais informações, consulte Considerações de desempenho (EF).
Próximos passos
Este é o primeiro de uma série de tutoriais que mostram como usar o Entity Framework (EF) Core em um aplicativo ASP.NET Core Razor Pages . Os tutoriais criam um site para uma Universidade Contoso fictícia. O site inclui funcionalidades como admissão de alunos, criação de cursos e tarefas de instrutores. O tutorial utiliza a abordagem code first, que prioriza o código. Para obter informações sobre como seguir este tutorial usando a primeira abordagem do banco de dados, consulte este problema do Github.
Transfira ou veja a aplicação concluída.Instruções para download.
Prerequisites
- Se você é novo no Razor Pages, consulte a série de tutoriais Introdução ao Razor Pages antes de iniciar esta.
Visual Studio 2022 com a carga de trabalho de ASP.NET e desenvolvimento web .
Mecanismos de banco de dados
As instruções do Visual Studio usam SQL Server LocalDB, uma versão do SQL Server Express que é executada somente no Windows.
Troubleshooting
Se você encontrar um problema que não pode resolver, compare seu código com o projeto concluído. Uma boa maneira de obter ajuda é postando uma pergunta para StackOverflow.com, usando a tag ASP.NET Core ou a EF Core tag .
O aplicativo de exemplo
O aplicativo construído nesses tutoriais é um site básico da universidade. Os usuários podem visualizar e atualizar informações de alunos, cursos e instrutores. Aqui estão algumas das telas criadas no tutorial.
Página 
O estilo da interface do usuário deste site é baseado nos modelos de projeto internos. O foco do tutorial está em como usar EF Core com o ASP.NET Core, não em como personalizar a interface do usuário.
Opcional: criar o download de exemplo
Esta etapa é opcional. A criação do aplicativo concluído é recomendada quando você tem problemas que não consegue resolver. Se você encontrar um problema que não pode resolver, compare seu código com o projeto concluído. Instruções para download.
Selecione ContosoUniversity.csproj para abrir o projeto.
- Construa o projeto.
- No Console do Gerenciador de Pacotes (PMC), execute o seguinte comando:
Update-Database
Execute o projeto para semear o banco de dados.
Criar o projeto de aplicativo Web
- Inicie o Visual Studio e selecione Criar um novo projeto.
- Na caixa de diálogo Criar um novo projeto, selecione Aplicação Web ASP.NET Core>Avançar.
- Na caixa de diálogo Configurar o novo projeto, digite
ContosoUniversitypara nome do projeto. É importante usar esse nome exato, incluindo maiúsculas, para que cadanamespacecorresponda quando o código é copiado. - Selecione Criar.
- Na caixa de diálogo Criar um novo aplicativo Web ASP.NET Core , selecione:
- .NET Core e ASP.NET Core 5.0 nas listas.
- ASP.NET Aplicação Web Core.
-
caixa de diálogo Criar

Configurar o estilo do site
Copie e cole o seguinte código no Pages/Shared/_Layout.cshtml arquivo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2021 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
O arquivo de layout define o cabeçalho, o rodapé e o menu do site. O código anterior faz as seguintes alterações:
- Substitua cada ocorrência de "ContosoUniversity" por "Contoso University". Há três ocorrências.
- As entradas de menu Home e Privacy são eliminadas.
- As inscrições são adicionadas para Sobre, Alunos, Cursos, Instrutores e Departamentos.
No Pages/Index.cshtml, substitua o conteúdo do arquivo pelo seguinte código:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="row mb-auto">
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 mb-4 ">
<p class="card-text">
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>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column position-static">
<p class="card-text mb-auto">
You can build the application by following the steps in a series of tutorials.
</p>
<p>
<a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column">
<p class="card-text mb-auto">
You can download the completed project from GitHub.
</p>
<p>
<a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
</p>
</div>
</div>
</div>
</div>
O código anterior substitui o texto sobre ASP.NET Core por texto sobre este aplicativo.
Execute o aplicativo para verificar se a página inicial aparece.
O modelo de dados
As seções a seguir criam um modelo de dados:
Um aluno pode se inscrever em qualquer número de cursos, e um curso pode ter qualquer número de alunos matriculados nele.
A entidade estudantil
Crie uma pasta Modelos na pasta do projeto.
Crie
Models/Student.cscom o seguinte código: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 ID propriedade se torna a coluna de chave primária da tabela de banco de dados que corresponde a essa classe. Por padrão, EF Core interpreta uma propriedade nomeada ID ou classnameID como a chave primária. Portanto, o nome alternativo reconhecido automaticamente para a chave primária da Student classe é StudentID. Para mais informações, consulte EF Core - Chaves.
A propriedade Enrollments é uma propriedade de navegação . As propriedades de navegação mantêm outras entidades que estão associadas a esta entidade. Neste caso, a Enrollments propriedade de uma Student entidade detém todas as Enrollment entidades que estão relacionadas com esse Aluno. Por exemplo, se uma linha Estudante no banco de dados tiver duas linhas de Inscrição relacionadas, a Enrollments propriedade de navegação conterá essas duas entidades de Inscrição.
No banco de dados, uma linha Inscrição estará relacionada a uma linha Aluno se sua StudentID coluna contiver o valor de ID do aluno. Por exemplo, suponha que uma linha Student tenha ID=1. As linhas de inscrição relacionadas terão StudentID = 1.
StudentID é uma chave estrangeira na tabela Inscrição.
A Enrollments propriedade é definida como ICollection<Enrollment> porque pode haver várias entidades de Registro relacionadas. Outros tipos de coleção podem ser usados, como List<Enrollment> ou HashSet<Enrollment>. Quando ICollection<Enrollment> é usado, EF Core cria uma HashSet<Enrollment> coleção por padrão.
A entidade de Inscrição
Crie Models/Enrollment.cs com o seguinte código:
using System.ComponentModel.DataAnnotations;
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; }
[DisplayFormat(NullDisplayText = "No grade")]
public Grade? Grade { get; set; }
public Course Course { get; set; }
public Student Student { get; set; }
}
}
A EnrollmentID propriedade é a chave primária, esta entidade usa o classnameID padrão em vez de ID por si só. Para um modelo de dados de produção, muitos desenvolvedores escolhem um padrão e o usam de forma consistente. Este tutorial usa ambos apenas para ilustrar que ambos funcionam. O uso ID sem classname facilita a implementação de alguns tipos de alterações no modelo de dados.
A propriedade Grade é um enum. O ponto de interrogação após a declaração de Grade tipo indica que a Grade propriedade é anulável. Uma nota nula é diferente de uma nota zero — nula significa que uma nota não é conhecida ou ainda não foi atribuída.
A propriedade StudentID é uma chave estrangeira e a propriedade de navegação correspondente é Student. Uma Enrollment entidade está associada a uma Student entidade, portanto, a propriedade contém uma única Student entidade.
A propriedade CourseID é uma chave estrangeira e a propriedade de navegação correspondente é Course. Uma entidade Enrollment está associada a uma entidade Course.
EF Core interpreta uma propriedade como uma chave estrangeira se ela for nomeada <navigation property name><primary key property name>. Por exemplo,StudentID é a chave estrangeira para Student propriedade de navegação, visto que a chave primária da entidade Student é ID. As propriedades da chave estrangeira também podem ser nomeadas <primary key property name>. Por exemplo, CourseID desde que a Course chave primária da entidade seja CourseID.
A entidade do Curso
Crie Models/Course.cs com o seguinte código:
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. Uma entidade Course pode estar relacionada com qualquer número de entidades Enrollment.
O DatabaseGenerated atributo permite que o aplicativo especifique a chave primária em vez de fazer com que o banco de dados a gere.
Crie o projeto para validar que não há erros do compilador.
Páginas de apoio ao estudante
Nesta seção, a ferramenta de andaime ASP.NET Core é usada para gerar:
- Uma EF Core
DbContextaula. O contexto é a classe principal que coordena a funcionalidade do Entity Framework para um determinado modelo de dados. Deriva da Microsoft.EntityFrameworkCore.DbContext classe. -
Razor páginas que executam operações de Criar, Ler, Atualizar e Excluir (CRUD) para entidade
Student.
- Crie uma pasta Páginas/Alunos .
- No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Páginas/Alunos e selecione Adicionar>Novo Item de Andaime.
- Na caixa de diálogo Adicionar Novo Item de Andaime :
- Na guia à esquerda, selecione Páginas comuns >> instaladas Razor
- Selecione Razor Páginas usando o Entity Framework (CRUD)>ADD.
- Na caixa de diálogo Adicionar Razor páginas usando o Entity Framework (CRUD):
- Na lista suspensa Classe modelo, selecione Estudante (ContosoUniversity.Models).
- Na linha da classe de contexto de dados, selecione o sinal de + (mais).
- Altere o nome do contexto de dados para terminar em
SchoolContextvez deContosoUniversityContext. O nome de contexto atualizado:ContosoUniversity.Data.SchoolContext - Selecione Adicionar para concluir a adição da classe de contexto de dados.
- Selecione Adicionar para concluir a caixa de diálogo Adicionar Razor páginas .
- Altere o nome do contexto de dados para terminar em
Se o andaime falhar com o erro 'Install the package Microsoft.VisualStudio.Web.CodeGeneration.Design and try again.', execute a ferramenta de andaime novamente ou veja esse problema do GitHub.
Os seguintes pacotes são instalados automaticamente:
Microsoft.EntityFrameworkCore.SqlServerMicrosoft.EntityFrameworkCore.ToolsMicrosoft.VisualStudio.Web.CodeGeneration.Design
Se a etapa anterior falhar, construa o projeto e tente novamente a etapa do andaime.
O processo de andaime:
- Cria Razor páginas na pasta Páginas/Alunos :
-
Create.cshtmleCreate.cshtml.cs -
Delete.cshtmleDelete.cshtml.cs -
Details.cshtmleDetails.cshtml.cs -
Edit.cshtmleEdit.cshtml.cs -
Index.cshtmleIndex.cshtml.cs
-
- Cria
Data/SchoolContext.cs. - Adiciona o contexto à injeção de dependência no
Startup.cs. - Adiciona uma cadeia de conexão de banco de dados ao
appsettings.json.
Cadeia de conexão de banco de dados
A ferramenta de andaime gera uma cadeia de conexão no appsettings.json arquivo.
A cadeia de conexão especifica o SQL Server LocalDB:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=CU-1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
O LocalDB é uma versão leve do Mecanismo de Banco de Dados do SQL Server Express e destina-se ao desenvolvimento de aplicativos, não ao uso em produção. Por padrão, o LocalDB cria .mdf arquivos no C:/Users/<user> diretório.
Atualizar a classe de contexto do banco de dados
A classe principal que coordena a EF Core funcionalidade para um determinado modelo de dados é a classe de contexto do banco de dados. O contexto é derivado de Microsoft.EntityFrameworkCore.DbContext. O contexto especifica quais entidades são incluídas no modelo de dados. Neste projeto, a classe é chamada SchoolContext.
Atualize Data/SchoolContext.cs com o seguinte código:
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext (DbContextOptions<SchoolContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
O código anterior muda do singular DbSet<Student> Student para o plural DbSet<Student> Students. Para fazer com que o código das Razor Páginas corresponda ao novo DBSet nome, faça uma alteração global a partir de:
_context.Student. Para: _context.Students.
São 8 ocorrências.
Como um conjunto de entidades contém várias entidades, muitos desenvolvedores preferem que os nomes de propriedade DBSet sejam plurais.
O código destacado:
- Cria uma DbSet<TEntity> propriedade para cada conjunto de entidades. Na EF Core terminologia:
- Um conjunto de entidades normalmente corresponde a uma tabela de banco de dados.
- Uma entidade corresponde a uma linha na tabela.
- Chamadas OnModelCreating.
OnModelCreating:- É chamado quando
SchoolContextfoi inicializado, mas antes que o modelo tenha sido protegido e usado para inicializar o contexto. - É obrigatório porque posteriormente no tutorial a
Studententidade terá referências às outras entidades.
- É chamado quando
Crie o projeto para verificar se não há erros do compilador.
Startup.cs
ASP.NET Core é construído com injeção de dependência. Serviços como o SchoolContext são registados com injeção de dependência durante a inicialização da aplicação. Os componentes que requerem esses serviços, como as Razor páginas, têm esses serviços disponibilizados através de parâmetros do construtor. O código do construtor que obtém uma instância de contexto de banco de dados é mostrado posteriormente no tutorial.
A ferramenta de andaime registrou automaticamente a classe de contexto com o contêiner de injeção de dependência.
O andaime adicionou as seguintes linhas destacadas:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
}
O nome da cadeia de conexão é passado para o contexto chamando um método em um objeto DbContextOptions. Para o desenvolvimento local, o sistema de configuração ASP.NET Core lê a cadeia de conexão do arquivo appsettings.json.
Adicionar o filtro de exceção do banco de dados
Adicionar AddDatabaseDeveloperPageExceptionFilter e UseMigrationsEndPoint como mostrado no código a seguir:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
services.AddDatabaseDeveloperPageExceptionFilter();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Adicione o pacote NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.
No Console do Gerenciador de Pacotes, digite o seguinte para adicionar o pacote NuGet:
Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
O Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore pacote NuGet fornece middleware ASP.NET Core para páginas de erro do Entity Framework Core. Esse middleware ajuda a detetar e diagnosticar erros com migrações do Entity Framework Core.
O AddDatabaseDeveloperPageExceptionFilter fornece informações úteis sobre erros no ambiente de desenvolvimento para erros de migrações do Entity Framework.
Criar a base de dados
Atualize Program.cs para criar o banco de dados se ele não existir:
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
namespace ContosoUniversity
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
CreateDbIfNotExists(host);
host.Run();
}
private static void CreateDbIfNotExists(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
// DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred creating the DB.");
}
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
O EnsureCreated método não executa nenhuma ação se existir um banco de dados para o contexto. Se nenhum banco de dados existir, ele criará o banco de dados e o esquema.
EnsureCreated Permite o seguinte fluxo de trabalho para lidar com alterações de modelo de dados:
- Exclua o banco de dados. Todos os dados existentes são perdidos.
- Altere o modelo de dados. Por exemplo, adicione um
EmailAddresscampo. - Execute o aplicativo.
-
EnsureCreatedCria um banco de dados com o novo esquema.
Esse fluxo de trabalho funciona no início do desenvolvimento, quando o esquema está evoluindo rapidamente, desde que os dados não precisem ser preservados. A situação é diferente quando os dados introduzidos na base de dados têm de ser preservados. Quando for esse o caso, use migrações.
Mais tarde na série de tutoriais, o banco de dados criado por EnsureCreated é excluído e utilizam-se migrações. Um banco de dados criado por EnsureCreated não pode ser atualizado usando migrações.
Testar a aplicação
- Execute o aplicativo.
- Selecione o link Alunos e, em seguida, Criar novo.
- Teste os links Editar, Detalhes e Excluir.
Semear o banco de dados
O EnsureCreated método cria um banco de dados vazio. Esta seção adiciona código que preenche o banco de dados com dados de teste.
Crie Data/DbInitializer.cs com o seguinte código:
using ContosoUniversity.Models;
using System;
using System.Linq;
namespace ContosoUniversity.Data
{
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
// Look for any students.
if (context.Students.Any())
{
return; // DB has been seeded
}
var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
};
context.Students.AddRange(students);
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}
};
context.Courses.AddRange(courses);
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},
};
context.Enrollments.AddRange(enrollments);
context.SaveChanges();
}
}
}
O código verifica se há algum aluno no banco de dados. Se não houver alunos, adiciona dados de teste ao banco de dados. Ele cria os dados de teste em matrizes em vez de List<T> coleções para otimizar o desempenho.
No
Program.cs, remova//daDbInitializer.Initializelinha:context.Database.EnsureCreated(); DbInitializer.Initialize(context);
Pare o aplicativo se ele estiver em execução e execute o seguinte comando no Console do Gerenciador de Pacotes (PMC):
Drop-Database -ConfirmResponda com
Ypara excluir o banco de dados.
- Reinicie o aplicativo.
- Selecione a página Alunos para ver os dados pré-definidos.
Ver a base de dados
- Abra o Pesquisador de Objetos do SQL Server (SSOX) no menu Exibir no Visual Studio.
- Em SSOX, selecione (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. O nome do banco de dados é gerado a partir do nome de contexto fornecido anteriormente, além de um traço e um GUID.
- Expanda o nó Tabelas .
- 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.
- Clique com o botão direito do rato na tabela Student e clique em Ver Código para ver como o modelo se mapeia
Studentpara o esquema daStudenttabela.
Código assíncrono
A programação assíncrona é o modo padrão para ASP.NET Core e 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. Quando isso acontece, o servidor não pode processar novas solicitações até que os threads sejam liberados. Com o código síncrono, muitos threads podem ficar presos enquanto não estão fazendo trabalho porque estão aguardando a conclusão da E/S. Com o código assíncrono, quando um processo está aguardando a conclusão da E/S, seu thread é liberado para o servidor usar para processar outras solicitações. Como resultado, o código assíncrono permite que os recursos do servidor sejam usados de forma mais eficiente e o servidor pode lidar com mais tráfego sem atrasos.
O código assíncrono introduz uma pequena quantidade de sobrecarga em tempo de execução. Para situações de baixo tráfego, o impacto no desempenho é insignificante, enquanto para situações de tráfego elevado, a melhoria potencial do desempenho é substancial.
No código a seguir, a palavra-chave assíncrona , Task o valor de retorno, await a palavra-chave e ToListAsync o método fazem com que o código seja executado de forma assíncrona.
public async Task OnGetAsync()
{
Students = await _context.Students.ToListAsync();
}
- A
asyncpalavra-chave diz ao compilador para:- Gere callbacks para partes do corpo do método.
- Crie o objeto Task que é retornado.
- O
Tasktipo de retorno representa o trabalho em andamento. - A palavra-chave
awaitfaz com que o compilador divida o método em duas partes. A primeira parte termina com a operação iniciada de forma assíncrona. A segunda parte é usada numa função de retorno que é chamada quando a operação é concluída. -
ToListAsyncé a versão assíncrona do método de extensãoToList.
Algumas coisas a ter em conta ao escrever código assíncrono que utiliza EF Core:
- Somente instruções que fazem com que consultas ou comandos sejam enviados ao banco de dados são executadas de forma assíncrona. Isso inclui
ToListAsync,SingleOrDefaultAsync,FirstOrDefaultAsync, eSaveChangesAsync. Ele não inclui declarações que apenas alteram umIQueryable, comovar students = context.Students.Where(s => s.LastName == "Davolio"). - Um EF Core contexto não é seguro para execução simultânea: não execute várias operações em paralelo.
- Para aproveitar os benefícios de desempenho do código assíncrono, verifique se os pacotes de biblioteca (como para paginação) usam async se chamarem EF Core métodos que enviam consultas para o banco de dados.
Para obter mais informações sobre programação assíncrona no .NET, consulte Visão geral assíncrona e Programação assíncrona com async e await.
Considerações sobre desempenho
Em geral, uma página da Web não deve carregar um número arbitrário de linhas. Uma consulta deve usar paginação ou uma abordagem limitante. Por exemplo, a consulta anterior pode ser usada Take para limitar as linhas retornadas:
public async Task OnGetAsync()
{
Student = await _context.Students.Take(10).ToListAsync();
}
Enumerar uma tabela extensa numa visualização pode retornar uma resposta HTTP 200 parcialmente construída se uma exceção de base de dados ocorrer a meio do processo de enumeração.
MaxModelBindingCollectionSize o padrão é 1024. O seguinte código define MaxModelBindingCollectionSize:
public void ConfigureServices(IServiceCollection services)
{
var myMaxModelBindingCollectionSize = Convert.ToInt32(
Configuration["MyMaxModelBindingCollectionSize"] ?? "100");
services.Configure<MvcOptions>(options =>
options.MaxModelBindingCollectionSize = myMaxModelBindingCollectionSize);
services.AddRazorPages();
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
services.AddDatabaseDeveloperPageExceptionFilter();
}
Consulte Configuração para obter informações sobre definições de configuração como MyMaxModelBindingCollectionSize.
A paginação é abordada mais adiante no tutorial.
Para obter mais informações, consulte Considerações de desempenho (EF).
Registo SQL do Entity Framework Core
A configuração de registo geralmente é fornecida pela seção Logging de arquivos appsettings.{Environment}.json. Para registrar instruções SQL, adicione "Microsoft.EntityFrameworkCore.Database.Command": "Information" ao arquivo appsettings.Development.json:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDB-2;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
,"Microsoft.EntityFrameworkCore.Database.Command": "Information"
}
},
"AllowedHosts": "*"
}
Com o JSON anterior, as instruções SQL são exibidas na linha de comando e na janela de saída do Visual Studio.
Para obter mais informações, consulte Fazendo login no .NET e no ASP.NET Core e este problema do GitHub.
Próximos passos
Este é o primeiro de uma série de tutoriais que mostram como usar o Entity Framework (EF) Core em um aplicativo ASP.NET Core Razor Pages . Os tutoriais criam um site para uma Universidade Contoso fictícia. O site inclui funcionalidades como admissão de alunos, criação de cursos e tarefas de instrutores. O tutorial utiliza a abordagem code first, que prioriza o código. Para obter informações sobre como seguir este tutorial usando a primeira abordagem do banco de dados, consulte este problema do Github.
Transfira ou veja a aplicação concluída.Instruções para download.
Prerequisites
- Se você é novo no Razor Pages, consulte a série de tutoriais Introdução ao Razor Pages antes de iniciar esta.
Visual Studio 2022 com a carga de trabalho de ASP.NET e desenvolvimento web .
Mecanismos de banco de dados
As instruções do Visual Studio usam SQL Server LocalDB, uma versão do SQL Server Express que é executada somente no Windows.
As instruções do Visual Studio Code usam SQLite, um mecanismo de banco de dados de plataforma cruzada.
Se você optar por usar o SQLite, baixe e instale uma ferramenta de terceiros para gerenciar e exibir um banco de dados SQLite, como o DB Browser for SQLite.
Troubleshooting
Se você encontrar um problema que não pode resolver, compare seu código com o projeto concluído. Uma boa maneira de obter ajuda é postando uma pergunta para StackOverflow.com, usando a tag ASP.NET Core ou a EF Core tag .
O aplicativo de exemplo
O aplicativo construído nesses tutoriais é um site básico da universidade. Os usuários podem visualizar e atualizar informações de alunos, cursos e instrutores. Aqui estão algumas das telas criadas no tutorial.
Página 
O estilo da interface do usuário deste site é baseado nos modelos de projeto internos. O foco do tutorial está em como usar EF Coree não em como personalizar a interface do usuário.
Siga o link na parte superior da página para obter o código-fonte do projeto concluído. A pasta cu30 tem o código para a versão ASP.NET Core 3.0 do tutorial. Os arquivos que refletem o estado do código para tutoriais 1-7 podem ser encontrados na pasta cu30snapshots .
Para executar o aplicativo depois de baixar o projeto concluído:
Construa o projeto.
No Console do Gerenciador de Pacotes (PMC), execute o seguinte comando:
Update-DatabaseExecute o projeto para semear o banco de dados.
Criar o projeto de aplicativo Web
- No menu Visual Studio Ficheiro, selecione Novo>Projeto.
- Selecione Aplicação Web ASP.NET Core.
- Nomeie o projeto como ContosoUniversity. É importante usar esse nome exato, incluindo maiúsculas, para que os namespaces correspondam quando o código é copiado e colado.
- Selecione .NET Core e ASP.NET Core 3.0 nas listas suspensas e, em seguida, selecione Aplicativo Web.
Configurar o estilo do site
Configure o cabeçalho, rodapé e menu do site atualizando Pages/Shared/_Layout.cshtml:
Altere cada ocorrência de "ContosoUniversity" para "Contoso University". Há três ocorrências.
Exclua as entradas e Home do Privacy menu e adicione entradas para Sobre, Alunos, Cursos, Instrutores e Departamentos.
As mudanças são destacadas.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2019 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
No Pages/Index.cshtml, substitua o conteúdo do arquivo pelo código a seguir para substituir o texto sobre ASP.NET Core por texto sobre este aplicativo:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="row mb-auto">
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 mb-4 ">
<p class="card-text">
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>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column position-static">
<p class="card-text mb-auto">
You can build the application by following the steps in a series of tutorials.
</p>
<p>
<a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row no-gutters border mb-4">
<div class="col p-4 d-flex flex-column">
<p class="card-text mb-auto">
You can download the completed project from GitHub.
</p>
<p>
<a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
</p>
</div>
</div>
</div>
</div>
Execute o aplicativo para verificar se a página inicial aparece.
O modelo de dados
As seções a seguir criam um modelo de dados:
Um aluno pode se inscrever em qualquer número de cursos, e um curso pode ter qualquer número de alunos matriculados nele.
A entidade estudantil
Crie uma pasta Modelos na pasta do projeto.
Crie
Models/Student.cscom o seguinte código: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 ID propriedade se torna a coluna de chave primária da tabela de banco de dados que corresponde a essa classe. Por padrão, EF Core interpreta uma propriedade nomeada ID ou classnameID como a chave primária. Portanto, o nome alternativo reconhecido automaticamente para a chave primária da Student classe é StudentID. Para mais informações, consulte EF Core - Chaves.
A propriedade Enrollments é uma propriedade de navegação . As propriedades de navegação mantêm outras entidades que estão associadas a esta entidade. Neste caso, a Enrollments propriedade de uma Student entidade detém todas as Enrollment entidades que estão relacionadas com esse Aluno. Por exemplo, se uma linha Estudante no banco de dados tiver duas linhas de Inscrição relacionadas, a Enrollments propriedade de navegação conterá essas duas entidades de Inscrição.
No banco de dados, uma linha Inscrição está relacionada a uma linha Estudante se sua coluna ID do Aluno contiver o valor da ID do aluno. Por exemplo, suponha que uma linha Student tenha ID=1. As linhas de matrícula relacionadas terão StudentID = 1. StudentID é uma chave estrangeira na tabela de matrícula.
A Enrollments propriedade é definida como ICollection<Enrollment> porque pode haver várias entidades de Registro relacionadas. Você pode usar outros tipos de coleção, como List<Enrollment> ou HashSet<Enrollment>. Quando ICollection<Enrollment> é usado, EF Core cria uma HashSet<Enrollment> coleção por padrão.
A entidade de Inscrição
Crie Models/Enrollment.cs com o seguinte código:
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 EnrollmentID propriedade é a chave primária, esta entidade usa o classnameID padrão em vez de ID por si só. Para um modelo de dados de produção, escolha um padrão e use-o de forma consistente. Este tutorial usa ambos apenas para ilustrar que ambos funcionam. O uso ID sem classname facilita a implementação de alguns tipos de alterações no modelo de dados.
A propriedade Grade é um enum. O ponto de interrogação após a declaração de Grade tipo indica que a Grade propriedade é anulável. Uma nota nula é diferente de uma nota zero — nula significa que uma nota não é conhecida ou ainda não foi atribuída.
A propriedade StudentID é uma chave estrangeira e a propriedade de navegação correspondente é Student. Uma Enrollment entidade está associada a uma Student entidade, portanto, a propriedade contém uma única Student entidade.
A propriedade CourseID é uma chave estrangeira e a propriedade de navegação correspondente é Course. Uma entidade Enrollment está associada a uma entidade Course.
EF Core interpreta uma propriedade como uma chave estrangeira se ela for nomeada <navigation property name><primary key property name>. Por exemplo,StudentID é a chave estrangeira para Student propriedade de navegação, visto que a chave primária da entidade Student é ID. As propriedades da chave estrangeira também podem ser nomeadas <primary key property name>. Por exemplo, CourseID desde que a Course chave primária da entidade seja CourseID.
A entidade do Curso
Crie Models/Course.cs com o seguinte código:
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. Uma entidade Course pode estar relacionada com qualquer número de entidades Enrollment.
O DatabaseGenerated atributo permite que o aplicativo especifique a chave primária em vez de fazer com que o banco de dados a gere.
Crie o projeto para validar que não há erros do compilador.
Páginas de apoio ao estudante
Nesta seção, use a ferramenta de andaime ASP.NET Core para gerar:
- Uma classe de EF Corecontexto . O contexto é a classe principal que coordena a funcionalidade do Entity Framework para um determinado modelo de dados. Deriva da
Microsoft.EntityFrameworkCore.DbContextclasse. -
Razor páginas que executam operações de Criar, Ler, Atualizar e Excluir (CRUD) para entidade
Student.
- Crie uma pasta Alunos na pasta Páginas .
- No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Páginas/Alunos e selecione Adicionar>Novo Item de Andaime.
- Na caixa de diálogo Adicionar andaime , selecione Razor Páginas usando o Entity Framework (CRUD)>ADD.
- Na caixa de diálogo Adicionar Razor páginas usando o Entity Framework (CRUD):
- Na lista suspensa Classe modelo, selecione Estudante (ContosoUniversity.Models).
- Na linha da classe de contexto de dados, selecione o sinal de + (mais).
- Altere o nome do contexto de dados de ContosoUniversity.Models.ContosoUniversityContext para ContosoUniversity.Data.SchoolContext.
- Selecione Adicionar.
Os seguintes pacotes são instalados automaticamente:
Microsoft.VisualStudio.Web.CodeGeneration.DesignMicrosoft.EntityFrameworkCore.SqlServerMicrosoft.Extensions.Logging.DebugMicrosoft.EntityFrameworkCore.Tools
Se você tiver um problema com a etapa anterior, construa o projeto e tente novamente a etapa do andaime.
O processo de andaime:
- Cria Razor páginas na pasta Páginas/Alunos :
-
Create.cshtmleCreate.cshtml.cs -
Delete.cshtmleDelete.cshtml.cs -
Details.cshtmleDetails.cshtml.cs -
Edit.cshtmleEdit.cshtml.cs -
Index.cshtmleIndex.cshtml.cs
-
- Cria
Data/SchoolContext.cs. - Adiciona o contexto à injeção de dependência no
Startup.cs. - Adiciona uma cadeia de conexão de banco de dados ao
appsettings.json.
Cadeia de conexão de banco de dados
O appsettings.json arquivo especifica a cadeia de conexão SQL Server LocalDB.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=SchoolContext6;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
O LocalDB é uma versão leve do Mecanismo de Banco de Dados do SQL Server Express e destina-se ao desenvolvimento de aplicativos, não ao uso em produção. Por padrão, o LocalDB cria .mdf arquivos no C:/Users/<user> diretório.
Atualizar a classe de contexto do banco de dados
A classe principal que coordena a EF Core funcionalidade para um determinado modelo de dados é a classe de contexto do banco de dados. O contexto é derivado de Microsoft.EntityFrameworkCore.DbContext. O contexto especifica quais entidades são incluídas no modelo de dados. Neste projeto, a classe é chamada SchoolContext.
Atualize Data/SchoolContext.cs com o seguinte código:
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext (DbContextOptions<SchoolContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}
O código realçado cria uma DbSet<TEntity> propriedade para cada conjunto de entidades. Na EF Core terminologia:
- Um conjunto de entidades normalmente corresponde a uma tabela de banco de dados.
- Uma entidade corresponde a uma linha na tabela.
Como um conjunto de entidades contém várias entidades, as propriedades DBSet devem ser nomes plurais. Como a ferramenta de andaime criou umStudent DBSet, esta etapa o altera para plural Students.
Para fazer com que o código das Razor Páginas se adeque ao novo nome de DBSet, faça uma alteração global em todo o projeto de _context.Student para _context.Students. São 8 ocorrências.
Crie o projeto para verificar se não há erros do compilador.
Startup.cs
ASP.NET Core é construído com injeção de dependência. Os serviços (como o contexto do EF Core banco de dados) são registados com injeção de dependência durante a inicialização da aplicação. Os componentes que necessitam desses serviços (como Razor Pages) recebem esses serviços através de parâmetros do construtor. O código do construtor que obtém uma instância de contexto de banco de dados é mostrado posteriormente no tutorial.
A ferramenta de andaime registrou automaticamente a classe de contexto com o contêiner de injeção de dependência.
No
ConfigureServices, as linhas destacadas foram adicionadas pelo andaime:public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddDbContext<SchoolContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SchoolContext"))); }
O nome da cadeia de conexão é passado para o contexto chamando um método em um objeto DbContextOptions. Para o desenvolvimento local, o sistema de configuração ASP.NET Core lê a cadeia de conexão do arquivo appsettings.json.
Criar a base de dados
Atualize Program.cs para criar o banco de dados se ele não existir:
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
namespace ContosoUniversity
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
CreateDbIfNotExists(host);
host.Run();
}
private static void CreateDbIfNotExists(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
// DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred creating the DB.");
}
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
O EnsureCreated método não executa nenhuma ação se existir um banco de dados para o contexto. Se nenhum banco de dados existir, ele criará o banco de dados e o esquema.
EnsureCreated Permite o seguinte fluxo de trabalho para lidar com alterações de modelo de dados:
- Exclua o banco de dados. Todos os dados existentes são perdidos.
- Altere o modelo de dados. Por exemplo, adicione um
EmailAddresscampo. - Execute o aplicativo.
-
EnsureCreatedCria um banco de dados com o novo esquema.
Esse fluxo de trabalho funciona bem no início do desenvolvimento, quando o esquema está evoluindo rapidamente, desde que você não precise preservar dados. A situação é diferente quando os dados introduzidos na base de dados têm de ser preservados. Quando for esse o caso, use migrações.
Mais adiante no tutorial, elimina o banco de dados que foi criado por EnsureCreated e faz uso de migrações em vez disso. Um banco de dados criado por EnsureCreated não pode ser atualizado usando migrações.
Testar a aplicação
- Execute o aplicativo.
- Selecione o link Alunos e, em seguida, Criar novo.
- Teste os links Editar, Detalhes e Excluir.
Semear o banco de dados
O EnsureCreated método cria um banco de dados vazio. Esta seção adiciona código que preenche o banco de dados com dados de teste.
Crie Data/DbInitializer.cs com o seguinte código:
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using System;
using System.Linq;
namespace ContosoUniversity.Data
{
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
context.Database.EnsureCreated();
// Look for any students.
if (context.Students.Any())
{
return; // DB has been seeded
}
var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
};
context.Students.AddRange(students);
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}
};
context.Courses.AddRange(courses);
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},
};
context.Enrollments.AddRange(enrollments);
context.SaveChanges();
}
}
}
O código verifica se há algum aluno no banco de dados. Se não houver alunos, adiciona dados de teste ao banco de dados. Ele cria os dados de teste em matrizes em vez de List<T> coleções para otimizar o desempenho.
No
Program.cs, substitua a chamada deEnsureCreatedpor uma chamada deDbInitializer.Initialize:// context.Database.EnsureCreated(); DbInitializer.Initialize(context);
Pare o aplicativo se ele estiver em execução e execute o seguinte comando no Console do Gerenciador de Pacotes (PMC):
Drop-Database
Reinicie o aplicativo.
Selecione a página Alunos para ver os dados pré-definidos.
Ver a base de dados
- Abra o Pesquisador de Objetos do SQL Server (SSOX) no menu Exibir no Visual Studio.
- Em SSOX, selecione (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. O nome do banco de dados é gerado a partir do nome de contexto fornecido anteriormente, além de um traço e um GUID.
- Expanda o nó Tabelas .
- 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.
- Clique com o botão direito do rato na tabela Student e clique em Ver Código para ver como o modelo se mapeia
Studentpara o esquema daStudenttabela.
Código assíncrono
A programação assíncrona é o modo padrão para ASP.NET Core e 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. Quando isso acontece, o servidor não pode processar novas solicitações até que os threads sejam liberados. Com o código síncrono, muitas threads podem ser bloqueadas sem realizar nenhum trabalho porque estão aguardando a conclusão das operações de E/S. Com o código assíncrono, quando um processo está aguardando a conclusão da E/S, seu thread é liberado para o servidor usar para processar outras solicitações. Como resultado, o código assíncrono permite que os recursos do servidor sejam usados de forma mais eficiente e o servidor pode lidar com mais tráfego sem atrasos.
O código assíncrono introduz uma pequena quantidade de sobrecarga em tempo de execução. Para situações de baixo tráfego, o impacto no desempenho é insignificante, enquanto para situações de tráfego elevado, a melhoria potencial do desempenho é substancial.
No código a seguir, a palavra-chave assíncrona , Task<T> o valor de retorno, await a palavra-chave e ToListAsync o método fazem com que o código seja executado de forma assíncrona.
public async Task OnGetAsync()
{
Students = await _context.Students.ToListAsync();
}
- A
asyncpalavra-chave diz ao compilador para:- Gere callbacks para partes do corpo do método.
- Crie o objeto Task que é retornado.
- O
Task<T>tipo de retorno representa o trabalho em andamento. - A palavra-chave
awaitfaz com que o compilador divida o método em duas partes. A primeira parte termina com a operação iniciada de forma assíncrona. A segunda parte é usada numa função de retorno que é chamada quando a operação é concluída. -
ToListAsyncé a versão assíncrona do método de extensãoToList.
Algumas coisas a ter em conta ao escrever código assíncrono que utiliza EF Core:
- Somente instruções que fazem com que consultas ou comandos sejam enviados ao banco de dados são executadas de forma assíncrona. Isso inclui
ToListAsync,SingleOrDefaultAsync,FirstOrDefaultAsync, eSaveChangesAsync. Ele não inclui declarações que apenas alteram umIQueryable, comovar students = context.Students.Where(s => s.LastName == "Davolio"). - Um EF Core contexto não é seguro para execução simultânea: não execute várias operações em paralelo.
- Para aproveitar os benefícios de desempenho do código assíncrono, verifique se os pacotes de biblioteca (como para paginação) usam async se chamarem EF Core métodos que enviam consultas para o banco de dados.
Para obter mais informações sobre programação assíncrona no .NET, consulte Visão geral assíncrona e Programação assíncrona com async e await.