Junção interna do EF Core

Resumo : neste tutorial, você aprenderá como usar o inner join para consultar dados de duas ou mais tabelas no EF Core.

Introdução ao EF Core Inner Join

Um departamento pode ter um ou mais funcionários, enquanto um funcionário pertence a um departamento. O relacionamento entre o departamento e o funcionário é um relacionamento um-para-muitos .

A Departmententidade mapeia para a Departmentstabela enquanto a Employeeentidade mapeia para a Employeestabela.

Aqui está o diagrama do banco de dados das tabelas Departmentse Employees:

As entidades Departmente Employeesão as seguintes:

public class Department
{
    public int Id { get; set; }
    public required string Name { get; set; }
}
namespace HR;


public class Employee
{
    public int Id { get; set; }
    public required string FirstName {  get; set; } 
    public required string LastName {  get; set; }
    public required decimal Salary { get; set; }
    public required DateTime JoinedDate { get; set; }
    
    // Foreign key property to the Department
    public int DepartmentId  {   get; set; }

    // Reference navigation to Department
    public Department Department { get; set; } = null!;

    // Reference navigation to EmployeeProfile
    public EmployeeProfile? Profile  { get; set; }

    // collection navigation to Employee
    public List<Skill> Skills { get; set; } = new();
}
Linguagem de código:  C#  ( cs )

Ao consultar os dados dos funcionários, você pode querer obter os departamentos que pertencem aos funcionários. Para fazer isso, você usa o Include()método do Employees DbSet.

Por exemplo, o programa a seguir usa o Include()método para obter os funcionários com seus departamentos e classificá-los pelo primeiro nome:

using HR;
using static System.Console;
using Microsoft.EntityFrameworkCore;

using var context = new HRContext();

// Get employees & departments
var employees = context.Employees.Include(e => e.Department)
                                 .OrderBy(e => e.FirstName)   
                                 .ToList();

foreach (var e in employees)
{
    WriteLine($"{e.FirstName} {e.LastName} - {e.Department.Name}");
}Linguagem de código:  C#  ( cs )

Saída:

Abigail Adams - Marketing
Addison Hill - Engineering
Aiden Wright - Marketing
Alexander Green - Finance
Alexander Young - Finance
Amelia Scott - Operations
...Linguagem de código:  C#  ( cs )

Nos bastidores, o EF Core gera uma instrução SQL que usa uma junção interna para consultar dados das tabelas Employeese :Departments

SELECT 
  [e].[Id], 
  [e].[DepartmentId], 
  [e].[FirstName], 
  [e].[JoinedDate], 
  [e].[LastName], 
  [e].[Salary],
  [d].[Id], 
  [d].[Name]
FROM 
  [Employees] AS [e] 
  INNER JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[Id] 
ORDER BY 
  [e].[FirstName]Linguagem de código:  C#  ( cs )

A instrução SQL une Employeesa Departmentstabela combinando os valores na DepartmentIdcoluna da Employeestabela com os valores na Idcoluna da Departmenttabela.

EF Core Inner Join em um relacionamento muitos para muitos

Um funcionário pode ter muitas habilidades e uma habilidade pode ser possuída por muitos funcionários. O relacionamento entre o funcionário e a habilidade é um relacionamento muitos para muitos .

O seguinte mostra a Skillclasse de entidade:

public class Skill
{
    public int Id  { get; set; }
    public required string Title  {   get;set;   }

    // collection navigation to Employee
    public List<Employee> Employees { get; set; } = new();
}Linguagem de código:  C#  ( cs )

Aqui está o diagrama do banco de dados que modela o relacionamento muitos-para-muitos entre entidades Employeee :Skill

Para obter funcionários com suas habilidades, você pode usar o Include()método Employees DbSeta seguir:

using HR;
using static System.Console;
using Microsoft.EntityFrameworkCore;

using var context = new HRContext();

var employees = context.Employees.Include(e => e.Skills)
                                 .OrderBy(e => e.FirstName)
                                 .ToList();


foreach (var e in employees)
{
    
    WriteLine($"{e.FirstName} {e.LastName}");

    foreach (var skill in e.Skills)
    {
        WriteLine($"- {skill.Title}");
    }
}Linguagem de código:  C#  ( cs )

Saída:

Abigail Adams
- Marketing Strategy
- Market Segmentation
Addison Hill
- Product Design
- Quality Assurance
Aiden Wright
- Market Trend Analysis
- Brand Development
...Linguagem de código:  C#  ( cs )

Neste exemplo, o EF Core primeiro une a EmployeeSkilltabela com a Skillstabela usando uma junção interna em uma subconsulta . E então ele une a Employeestabela com o conjunto de resultados retornado pela subconsulta usando um left join . Isso significa que a consulta retornará todos os funcionários, tenham ou não habilidades.

SELECT 
  [e].[Id], 
  [e].[DepartmentId], 
  [e].[FirstName], 
  [e].[JoinedDate], 
  [e].[LastName], 
  [e].[Salary],
  [t].[EmployeesId], 
  [t].[SkillsId], 
  [t].[Id], 
  [t].[Title] 
FROM 
  [Employees] AS [e] 
  LEFT JOIN (
    SELECT 
      [e0].[EmployeesId], 
      [e0].[SkillsId], 
      [s].[Id], 
      [s].[Title] 
    FROM 
      [EmployeeSkill] AS [e0] 
      INNER JOIN [Skills] AS [s] ON [e0].[SkillsId] = [s].[Id]
  ) AS [t] ON [e].[Id] = [t].[EmployeesId] 
ORDER BY 
  [e].[FirstName], 
  [e].[Id], 
  [t].[EmployeesId], 
  [t].[SkillsId]Linguagem de código:  C#  ( cs )

Usando múltiplas junções

Para obter os funcionários e seus departamentos e habilidades, você pode usar vários Include()métodos na mesma consulta:

using HR;
using static System.Console;
using Microsoft.EntityFrameworkCore;

using var context = new HRContext();

var employees = context.Employees.Include(e => e.Department)
                                 .Include(e => e.Skills)
                                 .OrderBy(e => e.FirstName)
                                 .ToList();


foreach (var e in employees)
{
    
    WriteLine($"{e.FirstName} {e.LastName} - {e.Department.Name}");

    foreach (var skill in e.Skills)
    {
        WriteLine($"- {skill.Title}");
    }
}Linguagem de código:  C#  ( cs )

Saída:

Abigail Adams - Marketing
- Marketing Strategy
- Market Segmentation
Addison Hill - Engineering
- Product Design
- Quality Assurance
Aiden Wright - Marketing
- Market Trend Analysis
- Brand DevelopmentLinguagem de código:  C#  ( cs )

O EF Core gera uma instrução SQL que possui várias cláusulas de junção. Primeiro, ele une a Employeestabela à Departmentstabela usando uma junção interna. E então ele se junta a uma subconsulta que inclui EmployeeSkilltabelas Skillsusando uma junção à esquerda:

SELECT 
  [e].[Id], 
  [e].[DepartmentId], 
  [e].[FirstName], 
  [e].[JoinedDate], 
  [e].[LastName], 
  [e].[Salary],
  [d].[Id], 
  [d].[Name], 
  [t].[EmployeesId], 
  [t].[SkillsId], 
  [t].[Id], 
  [t].[Title] 
FROM 
  [Employees] AS [e] 
  INNER JOIN [Departments] AS [d] ON [e].[DepartmentId] = [d].[Id] 
  LEFT JOIN (
    SELECT 
      [e0].[EmployeesId], 
      [e0].[SkillsId], 
      [s].[Id], 
      [s].[Title] 
    FROM 
      [EmployeeSkill] AS [e0] 
      INNER JOIN [Skills] AS [s] ON [e0].[SkillsId] = [s].[Id]
  ) AS [t] ON [e].[Id] = [t].[EmployeesId] 
ORDER BY 
  [e].[FirstName], 
  [e].[Id], 
  [d].[Id], 
  [t].[EmployeesId], 
  [t].[SkillsId]Linguagem de código:  C#  ( cs )

Resumo

  • Use DbSet Include()o método para formar uma junção interna (ou junção esquerda) no EF Core.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *