EF Core 2.1 - SQL Join com LINQ - I


 Neste artigo veremos como realizar consultas SQL Join com LINQ usando o Entity Framework Core 2.1.

As junções SQL são usadas para obter dados de duas ou mais tabelas, com base nos relacionamentos lógicos entre elas.

Podemos tratar quatro tipos de associações disponíveis com o SQL Server:

  1. Inner Join
  2. Outer Join
    1. Left Outer Join
    2. Rigth Outer Join
    3. Full Outer Join
  3. Cross Join
  4. Group Join

Abaixo vemos uma imagem expressando essas associações:

Para nos ajudar na tarefa de criar consultas SQL Join vamos usar os recursos da LINQ que oferece operadores JOIN.

Criando o projeto no VS 2017 Community e incluindo as referências

Vamos criar um projeto do tipo .NET Core do tipo Console App(.NET Core) com o nome de EFCore_Joins :

Crie uma pasta chamada Models no projeto (Project -> New Folder) onde vamos definir o modelo de entidades.

A seguir vamos incluir as seguintes referências no projeto:

Acesse o menu Tools -> Nuget Package Manager -> Manage Nuget Package for Solutions e clique na guia Browse;

A seguir localize o pacote desejado, selecione todos os projetos e clique no botão Install:

Faça isso para cada pacote de forma que ao final seu projeto deverá apresentar as referências Nuget:

Criando o modelo de entidades e a classe de contexto

Crie na pasta Models as classes Setor e Funcionario que representam o nosso modelo de entidades :

1 - Setor

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace EFCore_Joins.Models
{
    //entidade dependente(filha)
    public class Setor
    {
        public int SetorId { get; set; }
        [MaxLength(80)]
        public string SetorNome { get; set; }
    }
}

2 - Funcionario

using System.ComponentModel.DataAnnotations;
namespace EFCore_Joins.Models
{
    //Entidade principal (pai)
    public class Funcionario
    {
        public int FuncionarioId { get; set; }
        [MaxLength(80)]
        public string FuncionarioNome { get; set; }
        [MaxLength(80)]
        public string FuncionarioCargo { get; set; }
        public int? SetorId { get; set; }
    }
}

Observe que definimos a propriedade SetorId da entidade Funcionario como do tipo Nullable (int?) para que ao gerar a tabela a coluna  SetorId possa permitir valores null.

Nosso modelo de entidades não define um relacionamento entre as entidades pois vamos usar os recursos do SQL Join para obter os dados relacionados.

Agora vamos criar a classe AppDbContext que herda de DbContext e que representa a  nossa classe de contexto que é uma instância da classe DbContext e representa uma sessão com o banco de dados que pode ser usada para consultar e salvar instâncias de suas entidades em um banco de dados.

A classe DbContext é uma combinação dos padrões Unit Of Work e Repositóry.

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace EFCore_Joins.Models
{
    public class AppDbContext : DbContext
    {
        //mapeia as entidades para as tabelas do BD
        public DbSet<Setor> Setores { get; set; }
        public DbSet<Funcionario> Funcionarios { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //define o provedor do BD e a string de conexão
            optionsBuilder.UseSqlServer("Data Source=MACORATTI;" +
               "Initial Catalog=CursoEFCoreDB;Integrated Security=True");
             //exibe as consultas SQL no console
            optionsBuilder
             .EnableSensitiveDataLogging(true)
             .UseLoggerFactory(new LoggerFactory().AddConsole((category, level) =>
                level == LogLevel.Information &&
                category == DbLoggerCategory.Database.Command.Name, true));
        }
    }
}

No código acima definimos :

  1. O mapeamento das entidades para as tabelas;
  2. O provedor do banco de dados
  3. A string de conexão
  4. Habilitamos a exibição das consultas SQL no console (opcional)

Criando o banco de dados e as tabelas com Migrations

Vamos agora aplicar o Migrations para criar o banco de dados e as tabelas.

Para isso vamos usar os seguintes comandos na janela do Package Manager Console:

Abra uma janela do Package Manager Console e digite os comandos:

add-migration inicial

e a seguir

update-database

Pronto ! O banco de dados CursoEFCoreDB e as tabelas Funcionarios e Setores serão criados no banco de dados conforme mostra a figura abaixo:

 Alimentando as tabelas com dados iniciais

Vamos criar uma classe na pasta Models chamada SeedDatabase e definir o método estático PopulaDb conforme o código abaixo:

using System.Collections.Generic;
using System.Linq;
namespace EFCore_Joins.Models
{
    public class SeedDatabase
    {
        public static void PopulaDB(AppDbContext contexto)
        {
            contexto.Database.EnsureCreated();
            if (!contexto.Funcionarios.Any())
            {
                var setor1 = new Setor
                {
                    SetorNome = "Recursos Humanos",
                };
                contexto.Setores.Add(setor1);
                var funcionarios1 = new List<Funcionario>
                {
                   new Funcionario { FuncionarioNome="Marisa Monte", FuncionarioCargo="Gerente", SetorId= 1},
                   new Funcionario { FuncionarioNome="Janice Ribeiro", FuncionarioCargo="Administrativo", SetorId= 1}
                };
                contexto.Funcionarios.AddRange(funcionarios1);
                var setor2 = new Setor
                {
                    SetorNome = "Contabilidade",
                };
                contexto.Setores.Add(setor2);
                var funcionarios2 = new List<Funcionario>
                {
                     new Funcionario { FuncionarioNome="Pedro Toledo", FuncionarioCargo="Gerente", SetorId=2},
                     new Funcionario { FuncionarioNome="Andre Sanches", FuncionarioCargo="Contador", SetorId=2},
                     new Funcionario { FuncionarioNome="Hilda Hinst", FuncionarioCargo="Diretora"}
                };
                contexto.Funcionarios.AddRange(funcionarios2);
         
                var setor3 = new Setor
                {
                    SetorNome = "Marketing",
                };
                contexto.Setores.Add(setor3);
                var funcionarios3 = new List<Funcionario>
                {
                        new Funcionario { FuncionarioNome="Ana Maria Lima", FuncionarioCargo="Gerente", SetorId=3},
                        new Funcionario { FuncionarioNome="Carlos Ribeiro", FuncionarioCargo="Designer", SetorId=3},
                        new Funcionario { FuncionarioNome="Jaime Lacuste", FuncionarioCargo="CEO"},
                };
                contexto.Funcionarios.AddRange(funcionarios3);
                var setor4 = new Setor
                {
                     SetorNome = "Tecnologia",
                };
                contexto.Setores.Add(setor4);

                contexto.SaveChanges();
            }
        }
    }
}

Esta classe verifica se o banco de dados já foi criado e incluir 3 setores e seus respectivos funcionários.

Observe que estamos incluindo dois funcionários na tabela Funcionarios que não possuem um setor definido.(SetoId = Null), e, que também estamos incluindo  um Setor que não possui nenhum funcionário.

Vamos agora definir o código abaixo no método Main() do arquivo Program.cs para popular as tabelas do banco de dados criado:

using EFCore_Joins.Models;
using System;
namespace EFCore_Joins
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var contexto = new AppDbContext())
            {
                try
                {
                    SeedDatabase.PopulaDB(contexto);
                    Console.WriteLine("Concluído com sucesso");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Erro : " + ex.Message);
                }
            }
            Console.ReadLine();
        }
    }
}

Após executar a apllicação Console podemos consultar as tabelas do banco de dados CursoEFCoreDB :

Setores Funcionarios

Veja que a tabela funcionários possui dois funcionários 'sem um setor definido', e, que temos um setor (Tecnologia) sem funcionários atribuidos.

Temos assim as tabelas criadas e prontas para serem usadas.

No próximo artigo vou mostrar as consultas SQL Join.   

"Não pergunteis, pois, que haveis de comer, ou que haveis de beber, e não andeis inquietos."
"Porque as nações do mundo buscam todas essas coisas; mas vosso Pai sabe que precisais delas."
"Buscai antes o reino de Deus, e todas estas coisas vos serão acrescentadas."
Lucas 12:29-31

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti