Cláusulas Let, Group By e Order By no LINQ

Neste artigo eu vou demonstrar como utilizar as cláusulas let, group byorder by em uma consulta LINQ to SQL. Para ser objetivo, eu não vou mostrar nenhum mapeamento entre banco de dados e aplicação. Quando se trabalha com LINQ, percebemos que existe uma grande similaridade com a sintaxe de uma query no SQL Server. No exemplo abaixo, eu criei no banco uma tabela chamada tbFuncionarios:


create table tbFuncionarios

(

    ID            int          not null  primary key,

    Nome          varchar(50)  not null,

    Departamento  varchar(5)   not null,

    Salario       int          not null
) 

Suponha-se que eu quero saber o quanto cada funcionário ganha por departamento. Então, eu teria que fazer um agrupamento de funcionários por departamento e por salário (uma chave composta). No LINQ, o group by funciona da seguinte maneira:

– O agrupamento é dado por um objeto IGrouping<TKey, TElement>;

– O TElement representa o objeto que você quer agrupar (funcionario – definido na cláusula from) e depois de by vem a chave do agrupamento. No caso, quando temos uma chave composta definimos um tipo anônimo para tal, pela palavra-chave new;

– E, por fim, cria-se uma variável que vai armazenar o agrupamento (into f).

A cláusula let permite criar variáveis locais a uma query. Imagine que é solicitado a somatória do salário de todos os funcionários. O LINQ fornece um método de extensão, o Sum, que faz a soma dos valores dos objetos de uma coleção. Da mesma forma, o método Average, também de extensão, calcula a média aritmética simples dos valores de uma coleção. E o resultado disso é guardado nas variáveis salarioTotal e mediaSalarial.

A ordenação é feita pelas chaves Departamento e Salario em ordem crescente (por default), acessadas pela propriedade Key da variável de agrupamento. Se quiser aplicar uma ordenação decrescente, adicione a palavra-chave descending no final da cláusula orderby.


var query = from funcionario in context.tbFuncionarios
            group funcionario by new { funcionario.Departamento, funcionario.Salario } into f
            let salarioTotal = context.tbFuncionarios.Sum(x => x.Salario)
            let mediaSalarial = context.tbFuncionarios.Average(x => x.Salario)
            orderby f.Key.Departamento, f.Key.Salario
            select new
            {
               Salario = f.Key.Salario,
               Departamento = f.Key.Departamento,
               Total = salarioTotal,
               Media = mediaSalarial
            };

O resultado da query pode ser impresso por um foreach:


foreach (var func in query)
{
    Console.WriteLine("Departamento: " + func.Departamento + "\t" + "Salário: " + func.Salario); //etc..
}

Até a próxima,

Thiago

Anúncios

3 Respostas para “Cláusulas Let, Group By e Order By no LINQ

    • Gustavo,

      {SELECT [t5].[Salario], [t5].[Departamento], [t5].[value] AS [Total], [t5].[value2] AS [Media]
      FROM (
      SELECT [t3].[Departamento], [t3].[Salario], [t3].[value], (
      SELECT AVG([t4].[Salario])
      FROM [dbo].[tbFuncionarios] AS [t4]
      ) AS [value2]
      FROM (
      SELECT [t1].[Departamento], [t1].[Salario], (
      SELECT SUM([t2].[Salario])
      FROM [dbo].[tbFuncionarios] AS [t2]
      ) AS [value]
      FROM (
      SELECT [t0].[Departamento], [t0].[Salario]
      FROM [dbo].[tbFuncionarios] AS [t0]
      GROUP BY [t0].[Departamento], [t0].[Salario]
      ) AS [t1]
      ) AS [t3]
      ) AS [t5]
      ORDER BY [t5].[Departamento], [t5].[Salario]
      }

  1. Colega, antes de mais nada, parabéns pelo artigo e obrigado por partilhar aqui no grupo!
    Correndo o risco de parecer um velho apegado a tecnologias obsoletas – o que talvez eu seja, – eu não consigo entender qual é a vantagem de usar LInQ to SQL. LInQ to Objects é uma coisa da qual eu sentia falta, porque não havia um bom método de consultar objetos. Mas acrescentar uma camada extra a uma linguagem de consuta… Qual é a utilidade? Sem falar que a sintaxe é bem mais complicada que o SQL “tradicional”. E acrescentando que o SQL que é gerado é TERRÍVEl em termos de performance, é coisa de derrubar qualquer servidor de banco de dados! Por exemplo, tu publicaste no teu artigo, em resposta a uma pergunta, o código SQL que é gerado pelo LInQ. Uma série de SELECTs “aninhados”. Eu não entendi bem qual é o domínio do problema no eu exemplo, se é simplesmente obter o total e a média de salários por departamento, ou se é listar os funcionários juntamente com o total e a média por departamento. Em qualquer caso, usar SQL “puro”, me parece bem mais simples…
    Para obter o total e a média dos salários por departamento:
    SELECT Departamento, Avg(Salario), Sum(Salario) FROM Funcionarios GROUP BY Departamento;
    Para obter uma lista dos Funcionários que inclui o total e a média dos salários no Departamento de cada um:
    SELECT F,Nome, F.Departamento, F.Salario,
    DepTotais. Media, DepTotais.Total
    FROM Funcionarios F
    INNER JOIN
    (
    SELECT Departamento, Avg(Salario) as Media, Sum(Salario) as Total FROM Funcionarios GROUP BY Departamento
    ) as DepTotais
    ON Funcionarios.Departamento = DepTotais.Departamento;
    Admito que o segundo SELECT é um pouquinho mais complexo. Mas ainda assim é muito mais simples do que o gerado pelo LINQ. E MUITO mais otimizado.
    Colega, por favor, nota que eu não estou de forma nenhuma criticando o teu trabalho. Muito pelo contrário, só posso elogiar e agradecer.
    Estou apenas levantando um sincero questionamento, esperando que surja uma discussão do tema e que isso nos leve a um melhor entendimento dos recursos da nossa profissão!
    Obrigado, abraço!

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s