Olá! Te desejo as boas-vindas ao curso da Formação em Integração de Banco de Dados utilizando EF-Core. Meu nome é André Bessa e serei seu instrutor.
Audiodescrição: André se descreve como um homem negro, com barba por fazer, cabelo baixo e rosto arredondado. Veste uma camisa vermelha e o ambiente ao seu redor é iluminado com tons de azul. Ao fundo, uma estante com itens decorativos.
Antes de começarmos, é essencial que você tenha concluído o curso anterior, além de ter conhecimento em orientação a objetos, linguagem C# e bancos de dados.
Este curso é direcionado para quem já finalizou o curso anterior e deseja aprimorar ainda mais suas habilidades em integração de bases de dados utilizando Entity Framework Core, além de evoluir o sistema com boas práticas e padrões de projeto.
Ao longo do curso, vamos explorar como otimizar consultas com EF-Core, enriquecer nosso modelo de domínio utilizando Owned Entities e Value Converters. Também vamos aprofundar no uso de transações, adotando boas práticas como o Unit of Work e o padrão Repository. Além disso, aprenderemos a interceptar comandos que serão executados na base de dados.
Continuaremos o desenvolvimento do projeto Freelando, que você já conhece do curso anterior, melhorando desde seu banco de dados legado até a concepção geral do sistema.
Aproveite ao máximo os recursos da plataforma! Além dos vídeos e atividades, temos um fórum de dúvidas e uma comunidade ativa no Discord. Então, vamos começar?
Olá, pessoal!
Vamos dar continuidade à manutenção do projeto Freelando, que permite cadastrar e gerenciar projetos freelancer. Nosso foco é manter o processo de melhoria contínua, considerando que o banco de dados do Freelando é legado. Isso significa que seguimos um padrão definido anteriormente pela equipe de projetos, mas agora estamos integrando novos recursos com o Entity Framework.
No curso anterior, discutimos a importância da performance em consultas e vamos seguir a partir desse ponto. Um aspecto crucial das consultas é determinar se realmente precisamos de todas as informações de uma tabela. Por exemplo, ao abrir o endpoint de clientes, notamos que ele retorna todas as informações disponíveis na tabela, mas será que realmente precisamos de tudo?
Imagine um componente de front-end do tipo Select
que exibe apenas o nome do cliente. Nesse caso, trazer dados como endereço não faz sentido, além de impactar negativamente a performance.
Vamos otimizar esse endpoint de clientes para retornar apenas as informações necessárias. Para isso, selecionamos e copiamos o trecho de código. Depois, o colamos logo abaixo para editá-lo.
Trecho de código a ser duplicado:
app.MapGet("/clientes", async ([FromServices] ClienteConverter converter, [FromServices] FreelandoContext contexto) =>
{
var clientes = converter.EntityListToResponseList(contexto.Clientes.ToList());
return Results.Ok(await Task.FromResult(clientes));
})
.WithTags("Cliente")
.WithOpenApi();
No caso dos clientes, queremos retornar apenas o ID e o nome. Para isso, criaremos um novo endpoint chamado identificador-nome
, que nos permitirá comparar os resultados.
Vamos demonstrar como trabalhar com converters para aplicar essa funcionalidade. Primeiro, apagaremos o conteúdo da linha var clientes = converter.EntityListToResponseList(contexto.Clientes.ToList())
e substituiremos pelo seguinte trecho:
var clientes = contexto.Clientes.Select(c => new { Identificador = c.Id, Nome = c.Nome });
Nele, estamos criando uma lista de clientes utilizando o método .Select()
, do Linq, que permite selecionar apenas os campos desejados. Nesse caso, vamos selecionar o ID e o nome dos clientes. O objeto contexto
, que representa nosso banco de dados, será utilizado para acessar a tabela de clientes e criar um novo objeto contendo apenas essas informações essenciais de identificador e nome do cliente.
O código ficará assim:
app.MapGet("/clientes", async ([FromServices] ClienteConverter converter, [FromServices] FreelandoContext contexto) =>
{
var clientes = converter.EntityListToResponseList(contexto.Clientes.ToList());
return Results.Ok(await Task.FromResult(clientes));
})
.WithTags("Cliente")
.WithOpenApi();
app.MapGet("/clientes/identificador-nome", async ([FromServices] ClienteConverter converter, [FromServices] FreelandoContext contexto) =>
{
var clientes = contexto.Clientes.Select(c => new { Identificador = c.Id, Nome = c.Nome });
return Results.Ok(await Task.FromResult(clientes));
})
.WithTags("Cliente")
.WithOpenApi();
Depois de salvar, teremos um endpoint personalizado. Ao executar o projeto, o Swagger provavelmente será aberto em outra tela. No Swagger, navegaremos até a seção de clientes e selecionaremos o endpoint /clientes/identificador-nome
. Clicamos neste endpoint, depois em "Try it out", e executamos a consulta.
Como esperado, o resultado exibido contém apenas o identificador e o nome dos clientes, confirmando que a consulta personalizada está funcionando corretamente.
Essa abordagem otimiza o uso do banco de dados, já que, em vez de trazer todas as colunas da tabela, que podem variar dependendo da complexidade e dos relacionamentos, obtemos apenas um conjunto reduzido de informações.
Retornando ao endpoint identificador-nome
, utilizamos o operador Linq para criar um objeto anônimo, que não possui nome ou tipo definido, mas contém propriedades específicas. O compilador do .NET gera esse objeto, que é posteriormente convertido em JSON e exibido pela API.
Essa prática é crucial para otimizar nossas consultas, retornando apenas os dados necessários e, consequentemente, melhorando o desempenho geral da aplicação.
Na sequência, vamos continuar aprofundando o tema de performance em consultas.
Olá, pessoal!
Vamos continuar com a manutenção do nosso sistema, o Freelando, que utiliza uma base de dados legado. Estamos focados em melhorias e ajustes, especialmente na performance das consultas.
No vídeo anterior, abordamos como otimizar consultas trazendo apenas os dados essenciais utilizando a função .Select()
do Linq para criar objetos anônimos, o que facilita o retorno de dados apenas necessários para o front-end e para o Swagger.
Agora, vamos nos concentrar em um aspecto importante das consultas: o trabalho com dados relacionados. Por exemplo, queremos obter informações das tabelas de cliente, projeto e especialidade. Para isso, montaremos uma consulta SELECT
que pode incluir INNER JOIN
, LEFT JOIN
, OUTER JOIN
, ou até mesmo subselect. Em suma, uma consulta mais complexa.
Vamos analisar esse cenário utilizando a tabela de clientes. Criaremos um novo endpoint chamado cliente/projeto-especialidade
, com o objetivo de trazer informações de clientes, seus projetos e especialidades.
app.MapGet("/clientes/projeto-especialidade", async ([FromServices] ClienteConverter converter, [FromServices] FreelandoContext contexto) =>
{
var clientes = contexto.Clientes.Include(x => x.Projetos).ThenInclude(p => p.Especialidades).ToList();
return Results.Ok(await Task.FromResult(clientes));
}).WithTags("Cliente").WithOpenApi();
Se o seu projeto estiver com o AsNoTracking habilitado, você conseguirá trazer os dados relacionados na consulta. Aqui, utilizaremos as funções Include()
e ThenInclude()
para realizar essas junções, que serão convertidas em inner joins ou left joins, dependendo da necessidade, para buscar os dados nas tabelas.
Depois de configurar essa consulta, vamos salvar e executá-la para verificar os resultados.
Ao abrir o Swagger e executar o novo endpoint cliente/projeto-especialidade
, podemos observar que a consulta funciona conforme esperado. Os dados dos projetos e especialidades relacionados aos clientes estão sendo retornados corretamente.
Ao analisar o resultado no console, observamos que ele gerou um único SELECT
, um comando bastante complexo, onde realiza um LEFT JOIN
dentro de um subselect que abrange projetos, clientes e especialidades, seguido por outro LEFT JOIN
e finalizado com um INNER JOIN
. É uma consulta complexa!
Retorno omitido.
.AsSplitQuery()
Agora, é importante destacar que, ao trabalharmos com essas tabelas, que podem conter um grande volume de registros, esse tipo de Select
pode impactar a performance da consulta, dependendo do tamanho da base de dados. Mas há uma forma de melhorar essa performance.
Em cliente/projeto-especialidade
, especificamente na linha var clientes
, podemos instruir o sistema a pegar essa consulta e dividi-la em duas ou três subconsultas menores. Essas subconsultas podem ser mais eficientes na execução dos comandos no banco de dados. Para isso, antes de .ToList()
, usaremos .AsSplitQuery()
, uma extensão do Linq.
app.MapGet("/clientes/projeto-especialidade", async ([FromServices] ClienteConverter converter, [FromServices] FreelandoContext contexto) =>
{
var clientes = contexto.Clientes.Include(x => x.Projetos).ThenInclude(p => p.Especialidades).AsSplitQuery().ToList();
return Results.Ok(await Task.FromResult(clientes));
}).WithTags("Cliente").WithOpenApi();
Agora, vamos executar novamente o projeto, abrir o Swagger e também o terminal do servidor.
Ao executar a consulta cliente/projeto-especialidade
, note que ela continua funcionando como esperado, retornando os dados relacionados. Contudo, observe o que acontece no terminal: ao invés de uma única consulta complexa, o sistema executou pelo menos três consultas menores.
Retorno omitido.
Primeiro, ele realizou um SELECT
em clientes, depois um SELECT
com um INNER JOIN
nos projetos, e, finalmente, um SELECT
mais elaborado. Ao quebrar a consulta dessa forma, conseguimos otimizar a performance do banco de dados, que é exatamente o que buscamos.
Utilizando a função .AsSplitQuery()
, dividimos uma consulta única em consultas menores e menos complexas. Essa abordagem impacta positivamente a execução das consultas no banco de dados, algo essencial para o processo de evolução e melhoria contínua do nosso projeto.
É importante lembrar que essa é uma etapa de manutenção do projeto Freelando. Refatorações como essa, assim como a adição de novas funcionalidades, são fundamentais neste processo.
A divisão das consultas é útil porque, ao realizarmos joins entre tabelas, corremos o risco de enfrentar uma explosão cartesiana. Isso ocorre quando o banco de dados precisa relacionar grandes volumes de informações de diferentes tabelas, o que pode consumir muitos recursos do servidor. Ao quebrar a consulta em partes menores, conseguimos otimizar esse processo.
A Microsoft também aborda essa questão na seção "Consultas únicas vs. consultas divididas" da documentação, onde destaca problemas de desempenho, como a explosão cartesiana, e sugere boas práticas para evitar esses problemas ao utilizar o EF-Core.
A seguir, continuaremos focados na melhoria de performance das consultas enquanto trabalhamos no Freelando. Espero você no próximo vídeo!
O curso .NET: avance na persistência com EF Core possui 88 minutos de vídeos, em um total de 54 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:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.
Acesso completo
durante 1 ano
Estude 24h/dia
onde e quando quiser
Novos cursos
todas as semanas