Alura > Cursos de Programação > Cursos de .NET > Conteúdos de .NET > Primeiras aulas do curso Persistência de dados em .NET: use bancos relacionais e NoSQL

Persistência de dados em .NET: use bancos relacionais e NoSQL

Explorando stored procedure - Apresentação

Olá, meu nome é André Bessa e serei a pessoa instrutora neste curso na plataforma da Alura. Por questões de acessibilidade, vou me autodescrever.

Audiodescrição: André se identifica como um homem negro. Tem olhos e cabelos escuros. Usa barba, aparelho ortodôntico e camiseta vermelha. Ao fundo, ambiente iluminado pela cor azul com estante e decorações na parede.

Boas-vindas ao curso de integração de aplicações .NET com banco de dados.

Pré-requisitos

É recomendado que você tenha realizado os dois cursos desta formação Aprofunde .NET com Entity Framework Core. É importante também ter conhecimentos em C#, orientação a objetos, bancos de dados relacionais e não-relacionais, como por exemplo, o MongoDB. Inclusive, você pode conferir outros cursos na plataforma com esses assuntos.

O que vamos aprender?

Este conteúdo é destinado a quem deseja se aprofundar em como integrar banco de dados relacionais e não-relacionais na plataforma do .NET.

Você vai aprender a executar stored procedures que trabalham com projeção de consulta e recebimento de parâmetros, além de utilizar operações em lote (bulk operations) com banco de dados relacional no contexto do Entity Framework Core (EF Core).

Também aprendemos a como persistir e recuperar informações em cache, otimizando a execução de operações de consulta no banco de dados e a identificar e corrigir falhas de segurança, como SQL Injection.

Além disso, utilizaremos o pacote EF Tools para a criação de migrações e o scaffolding para fazer uma engenharia reversa a partir do banco de dados. Por fim, vamos salvar informações em um banco de dados não-relacional, como o MongoDB.

Vamos explorar tudo isso a partir de dois projetos. O Freelando, com o qual já estamos trabalhando na formação, que é um site que permite cadastrar clientes e profissionais para projetos freelance. E a novidade é o projeto ClickBônus, que vai permitir que clientes se cadastrem para receber bônus de oferta.

Além dos vídeos, contamos com atividades, apoio do fórum e da comunidade do Discord da Alura. Então, vamos estudar?

Explorando stored procedure - Chamando a Stored Procedure

Continuamos trabalhando com o Freelando, que é um banco de dados legado com o qual temos nos aprofundado durante a formação. Vamos partir de um ponto que discutimos no curso anterior, que são as stored procedures (procedimento armazenado).

Por se tratar de um banco de dados que já tem uma história, foi adicionada uma série de stored procedures para essa nova versão do Freelando que precisaremos usar agora, além de expor essas funcionalidades através de endpoints.

Chamando e executando stored procedures

Vamos abrir a ferramenta de banco de dados do Microsoft SQL Server com o banco de dados do Freelando.

No painel de pesquisador de objetos na lateral esquerda, podemos expandir a opção "Programação" para conferir as stored procedures com as quais vamos trabalhar (sp_BuscarTodasPropostas, sp_PropostaPorProjeto e sp_PropostaSummary) e também as que trabalhamos no curso anterior (sp_InserirProposta).

De volta ao projeto Freelando API, vamos acessar o painel de gerenciador de soluções na lateral direita do Visual Studio. No diretório "Endpoints", já adicionamos uma classe PropostasExtensions.

Baixe o template do projeto na atividade anterior de "Preparando o ambiente".

No método estático AddEndPointPropostas(), vamos adicionar o nosso primeiro endpoint. Primeiro, vamos colar uma estrutura básica para começar a trabalhar. Será um GET para a rota /propostas. Nele, vamos fazer uso do IIUnitOfWork.

PropostasExtensions.cs:

using Freelando.Dados.IUnitOfWork;
using Freelando.Modelos;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Runtime.InteropServices;
using System.Text.Json;

namespace Freelando.Api.Endpoints;
public static class PropostasExtensions
{
    public static void AddEndPointPropostas(this WebApplication app)
    {
        app.MapGet("/propostas", async ([FromServices] IIUnitOfWork unitOfOrk) =>
        {

        }).WithTags("Propostas").WithOpenApi();
    }
}

Para executar a stored procedure, vamos começar criando uma variável var chamada propostas que recebe um await unitOfOrk, porque estamos trabalhando com o banco de dados, utilizando o conceito de programação assíncrona.

Em seguida, adicionamos um .contexto, que é uma exposição que fizemos do contexto do Entity Framework Core, para poder executar funções mais específicas. Depois, acrescentamos .propostas, que é o DBSet.

Por fim, vamos executar o comando FromSqlRaw(), que vai permitir escrever o comando que poderíamos executar no banco de dados. Entre parênteses e aspas duplas, vamos colar o comando EXEC dbo.sp_BuscarTodasPropostas. Fora dos parênteses, vamos acrescentar .ToListAsync().

Como já fizemos a consulta, precisamos retornar. Na próxima linha, escrevemos return Results.Ok() para retornar a lista de propostas.

public static void AddEndPointPropostas(this WebApplication app)
{
        app.MapGet("/propostas", async ([FromServices] IIUnitOfWork unitOfOrk) =>
        {
                var propostas = await unitOfOrk.contexto.Propostas.FromSqlRaw("EXEC dbo.sp_BuscarTodasPropostas").ToListAsync();

             return Results.Ok(propostas);

        }).WithTags("Propostas").WithOpenApi();
}

Após salvar o arquivo, vamos executar a stored procedure através do endpoint. Basta clicar na opção "HTTPS", na barra de ferramentas localizada na parte superior do Visual Studio, para executar o projeto.

No navegador, abre-se o Swagger, onde vamos navegar até o endpoint de propostas. Podemos selecioná-lo, clicar no botão "Try it out" e depois no botão "Execute".

Conseguimos executar a stored procedure, que como o próprio nome dela já sugere, está fazendo uma consulta no banco de dados.

Corpo da resposta do endpoint https://localhost:7177/propostas:

[
  {
    "id": "56dd4990-e79a-4d44-8516-02caf9644357",
    "profissionalId": "409619ff-8b86-d011-b42d-00c04fc964ff",
    "projetoId": "1f9619ff-8b86-d011-b42d-00c04fc964ff",
    "valorProposta": 2123.11,
    "dataProposta": "2023-07-11T10:15:30.047",
    "mensagem": "Refatoração para clean arch",
    "prazoEntrega": "2023-08-10T00:00:00"
  },
  {
    "id": "7be72420-405c-4d31-8584-d113275096f1",
    "profissionalId": "409619ff-8b86-d011-b42d-00c04fc964ff",
    "projetoId": "1f9619ff-8b86-d011-b42d-00c04fc964ff",
    "valorProposta": 5201.12,
    "dataProposta": "2023-07-12T10:15:30.047",
    "mensagem": "Projeto implementação Microserviços",
    "prazoEntrega": "2023-08-11T00:00:00"
  }
]

Conclusão

Nesse vídeo, criamos um novo endpoint, que executa uma stored procedure chamada sp_BuscarTodasPropostas.

Uma stored procedure é um procedimento armazenado no banco de dados que pode armazenar regras de negócio ou uma lógica no próprio banco de dados.

Uma das formas de executar esse procedimento no nosso banco de dados é executando o comando EXEC seguido do nome da stored procedure.

Na sequência, vamos continuar trabalhando com as outras stored procedures que foram adicionadas para o projeto Freelando.

Explorando stored procedure - Passagem de parâmetros

Estamos de volta no projeto Freelando. Acabamos de criar um endpoint que executa uma stored procedure (SP) no banco de dados do SQL Server. No entanto, devemos executar outra stored procedure agora.

Vamos abrir novamente o banco de dados no Microsoft SQL Server Management Studio para entender melhor a estrutura dessa stored procedure chamada sp_PropostaPorProjeto.

Ao clicar com o botão direito em cima dela e selecionar a opção "Modificar", podemos conferir o conteúdo dessa stored procedure.

USE [Freelando]
GO

/****** Object: StoredProcedure [dbo].[sp_PropostaPorProjeto] Script Date: 12/08/2024 10:18:18 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[sp_PropostaPorProjeto]
@Id_Projeto uniqueidentifier
AS
BEGIN
    SELECT Id_Proposta, Id_Projeto, Id_Profissional, Valor_Proposta, Data_Proposta, Mensagem, Prazo_Entrega
    FROM dbo.TB_Propostas WHERE Id_Projeto = @Id_Projeto
END

Ela realiza um SELECT na tabela de TB_propostas, mas esse comando tem um parâmetro, um filtro que será o Id_Projeto. Como não queremos modificar nada, podemos apenas fechar a janela.

Executando stored procedures com parâmetros

No arquivo PropostasExtensions.cs no Visual Studio, vamos criar um novo endpoint para executar essa stored procedure. Já preparamos a estrutura desse endpoint e vamos colá-lo em AddEndPointPropostas().

PropostasExtensions.cs:

public static void AddEndPointPropostas(this WebApplication app)
{
        // código omitido…

        app.MapGet("/propostas/projeto", async ([FromServices] IUnitOfWork unitOfOrk, [FromQuery] Guid id_projeto) =>
        {

        }).WithTags("Propostas").WithOpenApi();

}

Também é um GET para a rota /propostas/projeto e receberá como parâmetro o Guid id_projeto.

Novamente, vamos criar novamente uma var propostas que recebe await, já que estamos trabalhando com programação assíncrona. Em seguida, escrevemos unitOfOrk.contexto.Propostas.FromSqlRaw().

No FromSqlRaw(), devemos passar tanto a stored procedure quanto o parâmetro. Entre aspas, vamos colar o comando que vamos executar. Nesse caso, será EXEC e o nome da stored procedure, dbo.sp_PropostaPorProjeto, como fizemos no endpoint anterior. Porém, também passamos o parâmetro, @id_projeto={0}.

Para informar o ID do projeto, vamos adicionar uma vírgula, ainda dentro do FromSqlRaw, mas fora das aspas, para colocar id_projeto. Fora dos parênteses, acrescentamos .ToListAsync().

Essa é a maneira de executar uma stored procedure que recebe parâmetros.

Finalmente, completamos com return Results.Ok() nas propostas.

public static void AddEndPointPropostas(this WebApplication app)
{
        // código omitido…

        app.MapGet("/propostas/projeto", async ([FromServices] IUnitOfWork unitOfOrk, [FromQuery] Guid id_projeto) =>
        {
                var propostas = await unitOfOrk.contexto.Propostas.FromSqlRaw("EXEC dbo.sp_PropostaPorProjeto @id_projeto={0}", id_projeto).ToListAsync();

                return Results.Ok(propostas);

        }).WithTags("Propostas").WithOpenApi();

}

Vamos salvar o arquivo e testar o novo endpoint, clicando no botão "HTTPS".

No Swagger, vamos consultar as propostas cadastradas primeiramente para pegar o ID do projeto. Selecionando GET /propostas, clicamos no botão "Try it out" e, em seguida, em "Execute".

No corpo da resposta, vamos copiar o valor da chave projetoID do primeiro projeto com o atalho "Ctrl + C":

1f9619ff-8b86-d011-b42d-00c04fc964ff

Agora, vamos acessar o endpoint que acabamos de criar, GET /propostas/projeto. Após apertar "Try it out", vamos colar o ID do projeto no campo obrigatório chamado "id_projeto". Depois, vamos clicar no botão "Execute".

Corpo da resposta do endoint https://localhost:7177/propostas/projeto?id_projeto=1f9619ff-8b86-d011-b42d-00c04fc964ff:

[
  {
    "id": "56dd4990-e79a-4d44-8516-02caf9644357",
    "profissionalId": "409619ff-8b86-d011-b42d-00c04fc964ff",
    "projetoId": "1f9619ff-8b86-d011-b42d-00c04fc964ff",
    "valorProposta": 2123.11,
    "dataProposta": "2023-07-11T10:15:30.047",
    "mensagem": "Refatoração para clean arch",
    "prazoEntrega": "2023-08-10T00:00:00"
  },
  {
    "id": "7be72420-405c-4d31-8584-d113275096f1",
    "profissionalId": "409619ff-8b86-d011-b42d-00c04fc964ff",
    "projetoId": "1f9619ff-8b86-d011-b42d-00c04fc964ff",
    "valorProposta": 5201.12,
    "dataProposta": "2023-07-12T10:15:30.047",
    "mensagem": "Projeto implementação Microserviços",
    "prazoEntrega": "2023-08-11T00:00:00"
  }
]

Note que as duas propostas cadastradas são para o mesmo projeto, pois tem o mesmo projetoId. Isso significa que a consulta está funcionando.

Conclusão

Nesse vídeo, criamos mais um endpoint que também executa uma stored procedure. A diferença é que essa stored procedure recebe um parâmetro.

Para isso, continuamos utilizando o FromSqlRaw(), mas informamos na string do comando que vamos utilizar o parâmetro, através da estrutura @nome-parametro e o valor que espera ser recebido, entre chaves. E, fora da string, passamos o parâmetro que será concatenado junto a esse comando.

Na sequência, vamos continuar trabalhando com as outras stored procedures do projeto.

Sobre o curso Persistência de dados em .NET: use bancos relacionais e NoSQL

O curso Persistência de dados em .NET: use bancos relacionais e NoSQL possui 124 minutos de vídeos, em um total de 55 atividades. Gostou? Conheça nossos outros cursos de .NET em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda .NET acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas