Tutorial: Usar procedimentos assíncronos e armazenados com o EF em um aplicativo MVC do ASP.NET
Nos tutoriais anteriores, você aprendeu a ler e atualizar dados usando o modelo de programação síncrona. Neste tutorial, você verá como implementar o modelo de programação assíncrona. O código assíncrono pode ajudar um aplicativo a ter um melhor desempenho porque faz melhor uso dos recursos do servidor.
Neste tutorial, você também verá como usar procedimentos armazenados para operações de inserção, atualização e exclusão em uma entidade.
Por fim, você reimplanta o aplicativo no Azure, juntamente com todas as alterações de banco de dados implementadas desde a primeira vez que implantou.
As ilustrações a seguir mostram algumas das páginas com as quais você trabalhará.
Neste tutorial, você:
- Saiba mais sobre código assíncrono
- Criar um controlador de departamento
- Usar procedimentos armazenados
- Implantar no Azure
Pré-requisitos
Por que usar código assíncrono
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 são liberados. 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. 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. Como resultado, o código assíncrono permite que os recursos do servidor sejam usados com mais eficiência e o servidor é habilitado para lidar com mais tráfego sem atrasos.
Em versões anteriores do .NET, escrever e testar código assíncrono era complexo, propenso a erros e difícil de depurar. No .NET 4.5, escrever, testar e depurar código assíncrono é muito mais fácil que você geralmente deve escrever código assíncrono, a menos que tenha um motivo para não fazê-lo. O código assíncrono introduz uma pequena quantidade de sobrecarga, mas para situações de baixo tráfego, o impacto no desempenho é insignificante, enquanto para situações de alto tráfego, a melhoria potencial do desempenho é substancial.
Para obter mais informações sobre programação assíncrona, consulte Usar o suporte assíncrono do .NET 4.5 para evitar o bloqueio de chamadas.
Criar controlador de departamento
Crie um controlador de departamento da mesma forma que você fez com os controladores anteriores, exceto que desta vez marque a caixa de seleção Usar ações do controlador assíncrono.
Os destaques a seguir mostram o que foi adicionado ao código síncrono para o Index
método para torná-lo assíncrono:
public async Task<ActionResult> Index()
{
var departments = db.Departments.Include(d => d.Administrator);
return View(await departments.ToListAsync());
}
Quatro alterações foram aplicadas para permitir que a consulta de banco de dados do Entity Framework seja executada de forma assíncrona:
- O método é marcado com a
async
palavra-chave, que informa ao compilador para gerar retornos de chamada para partes do corpo do método e criar automaticamente oTask<ActionResult>
objeto retornado. - O tipo de retorno foi alterado de
ActionResult
paraTask<ActionResult>
. OTask<T>
tipo representa o trabalho em andamento com um resultado do tipoT
. - A
await
palavra-chave foi aplicada à chamada de serviço da Web. Quando o compilador vê essa palavra-chave, nos bastidores, ele divide o método em duas partes. A primeira parte termina com a operação iniciada de forma assíncrona. A segunda parte é colocada em um método de retorno de chamada que é chamado quando a operação é concluída. - A versão assíncrona do
ToList
método de extensão foi chamada.
Por que a departments.ToList
declaração é modificada, mas não a departments = db.Departments
declaração? O motivo é que apenas as instruções que fazem com que consultas ou comandos sejam enviados ao banco de dados são executadas de forma assíncrona. A departments = db.Departments
instrução configura uma consulta, mas a consulta não é executada até que o ToList
método seja chamado. Portanto, apenas o ToList
método é executado de forma assíncrona.
No método e nos Details
HttpGet
Edit
métodos and Delete
, o Find
método é aquele que faz com que uma consulta seja enviada ao banco de dados, então esse é o método que é executado de forma assíncrona:
public async Task<ActionResult> Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Department department = await db.Departments.FindAsync(id);
if (department == null)
{
return HttpNotFound();
}
return View(department);
}
Create
Nos métodos , HttpPost Edit
, e DeleteConfirmed
, é a chamada de SaveChanges
método que faz com que um comando seja executado, não instruções como db.Departments.Add(department)
as que apenas fazem com que entidades na memória sejam modificadas.
public async Task<ActionResult> Create(Department department)
{
if (ModelState.IsValid)
{
db.Departments.Add(department);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
Abra Views\Department\Index.cshtml e substitua o código do modelo pelo seguinte código:
@model IEnumerable<ContosoUniversity.Models.Department>
@{
ViewBag.Title = "Departments";
}
<h2>Departments</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Budget)
</th>
<th>
@Html.DisplayNameFor(model => model.StartDate)
</th>
<th>
Administrator
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Budget)
</td>
<td>
@Html.DisplayFor(modelItem => item.StartDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Administrator.FullName)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.DepartmentID }) |
@Html.ActionLink("Details", "Details", new { id=item.DepartmentID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.DepartmentID })
</td>
</tr>
}
</table>
Esse código altera o título de Índice para Departamentos, move o nome do administrador para a direita e fornece o nome completo do administrador.
Nas visualizações Criar, Excluir, Detalhes e Editar, altere a legenda do InstructorID
campo para "Administrador" da mesma forma que você alterou o campo de nome do departamento para "Departamento" nas visualizações do curso.
Nas visualizações Criar e Editar, use o seguinte código:
<label class="control-label col-md-2" for="InstructorID">Administrator</label>
Nas exibições Excluir e Detalhes, use o seguinte código:
<dt>
Administrator
</dt>
Execute o aplicativo e clique na guia Departamentos .
Tudo funciona da mesma forma que nos outros controladores, mas neste controlador todas as consultas SQL são executadas de forma assíncrona.
Algumas coisas a serem observadas ao usar a programação assíncrona com o Entity Framework:
- O código assíncrono não é thread-safe. Em outras palavras, não tente fazer várias operações em paralelo usando a mesma instância de contexto.
- Se desejar aproveitar os benefícios de desempenho do código assíncrono, verifique se os pacotes de biblioteca que você está usando (por exemplo, para paginação) também usam o código assíncrono se eles chamam métodos do Entity Framework que fazem com que consultas sejam enviadas ao banco de dados.
Usar procedimentos armazenados
Alguns desenvolvedores e DBAs preferem usar procedimentos armazenados para acesso ao banco de dados. Em versões anteriores do Entity Framework, você pode recuperar dados usando um procedimento armazenado executando uma consulta SQL bruta, mas não pode instruir o EF a usar procedimentos armazenados para operações de atualização. No EF 6, é fácil configurar o Code First para usar procedimentos armazenados.
Em DAL\SchoolContext.cs, adicione o código realçado ao
OnModelCreating
método.protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Entity<Course>() .HasMany(c => c.Instructors).WithMany(i => i.Courses) .Map(t => t.MapLeftKey("CourseID") .MapRightKey("InstructorID") .ToTable("CourseInstructor")); modelBuilder.Entity<Department>().MapToStoredProcedures(); }
Esse código instrui o Entity Framework a usar procedimentos armazenados para operações de inserção, atualização e exclusão na
Department
entidade.No Console de Gerenciamento de Pacotes, insira o seguinte comando:
add-migration DepartmentSP
Abra Migrations\<timestamp_DepartmentSP.cs> para ver o código no
Up
método que cria os procedimentos armazenados Insert, Update e Delete:public override void Up() { CreateStoredProcedure( "dbo.Department_Insert", p => new { Name = p.String(maxLength: 50), Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"), StartDate = p.DateTime(), InstructorID = p.Int(), }, body: @"INSERT [dbo].[Department]([Name], [Budget], [StartDate], [InstructorID]) VALUES (@Name, @Budget, @StartDate, @InstructorID) DECLARE @DepartmentID int SELECT @DepartmentID = [DepartmentID] FROM [dbo].[Department] WHERE @@ROWCOUNT > 0 AND [DepartmentID] = scope_identity() SELECT t0.[DepartmentID] FROM [dbo].[Department] AS t0 WHERE @@ROWCOUNT > 0 AND t0.[DepartmentID] = @DepartmentID" ); CreateStoredProcedure( "dbo.Department_Update", p => new { DepartmentID = p.Int(), Name = p.String(maxLength: 50), Budget = p.Decimal(precision: 19, scale: 4, storeType: "money"), StartDate = p.DateTime(), InstructorID = p.Int(), }, body: @"UPDATE [dbo].[Department] SET [Name] = @Name, [Budget] = @Budget, [StartDate] = @StartDate, [InstructorID] = @InstructorID WHERE ([DepartmentID] = @DepartmentID)" ); CreateStoredProcedure( "dbo.Department_Delete", p => new { DepartmentID = p.Int(), }, body: @"DELETE [dbo].[Department] WHERE ([DepartmentID] = @DepartmentID)" ); }
No Console de Gerenciamento de Pacotes, insira o seguinte comando:
update-database
Execute o aplicativo no modo de depuração, clique na guia Departamentos e clique em Criar Novo.
Insira dados para um novo departamento e clique em Criar.
No Visual Studio, examine os logs na janela Saída para ver se um procedimento armazenado foi usado para inserir a nova linha Departamento.
O Code First cria nomes de procedimento armazenado padrão. Se você estiver usando um banco de dados existente, talvez seja necessário personalizar os nomes dos procedimentos armazenados para usar procedimentos armazenados já definidos no banco de dados. Para obter informações sobre como fazer isso, consulte Procedimentos armazenados de inserção/atualização/exclusão do Entity Framework Code First.
Se você quiser personalizar o que os procedimentos armazenados gerados fazem, poderá editar o código scaffolded para o método migrations Up
que cria o procedimento armazenado. Dessa forma, suas alterações são refletidas sempre que a migração for executada e serão aplicadas ao banco de dados de produção quando as migrações forem executadas automaticamente na produção após a implantação.
Se você quiser alterar um procedimento armazenado existente que foi criado em uma migração anterior, poderá usar o comando Add-Migration para gerar uma migração em branco e, em seguida, escrever manualmente o código que chama o método AlterStoredProcedure .
Implantar no Azure
Esta seção requer que você tenha concluído a seção opcional Implantando o aplicativo no Azure no tutorial Migrações e implantação desta série. Se você teve erros de migração que resolveu excluindo o banco de dados em seu projeto local, ignore esta seção.
No Visual Studio, clique com o botão direito do mouse no projeto no Gerenciador de Soluções e selecione Publicar no menu de contexto.
Clique em Publicar.
O Visual Studio implanta o aplicativo no Azure e o aplicativo é aberto no navegador padrão, em execução no Azure.
Teste o aplicativo para verificar se ele está funcionando.
Na primeira vez que você executa uma página que acessa o banco de dados, o Entity Framework executa todos os métodos de migração
Up
necessários para atualizar o banco de dados com o modelo de dados atual. Agora você pode usar todas as páginas da Web adicionadas desde a última vez que implantou, incluindo as páginas de departamento adicionadas neste tutorial.
Obter o código
Recursos adicionais
Links para outros recursos do Entity Framework podem ser encontrados no ASP.NET Acesso a Dados – Recursos Recomendados.
Próximas etapas
Neste tutorial, você:
- Aprendeu sobre código assíncrono
- Criou um controlador de departamento
- Procedimentos armazenados usados
- Implantado no Azure
Avance para o próximo artigo para saber como lidar com conflitos quando vários usuários atualizam a mesma entidade ao mesmo tempo.