LINQ to Objects permite aos desenvolvedores da plataforma .NET escrever "consultas" sobre coleções de objetos. Para facilitar a Microsoft fornece um grande conjunto de operadores de consulta, e esses operadores oferecem uma profundidade semelhante à funcionalidade que temos com a linguagem SQL trabalhando com banco de dados relacional. |
Neste artigo vamos rever alguns conceitos chaves da LINQ to Objects e mostrar na prática a sua utilização criando consultas em coleções de objetos para lembrar a sintaxe usada nessas operações.
Nota: Não Confunda LINQ to Objects com LINQ to Entities, elas são diferentes.
Tradicionalmente,
trabalhar com coleções de objetos significava escrever um monte de código usando
laços for ou foreach para percorrer a coleção, usar ifs
para filtrar durante a execução e manter uma soma parcial de uma
propriedade total.
A LINQ nos libera de ter que escrever o código usando muitos laços; ela permite
escrever consultas que filtram uma lista que façam cálculos usando funções de
agregação de elementos em uma coleção em memória.
Podemos escrever consultas contra qualquer tipo de coleção que implementa uma interface IEnumerable<T>, o que a grande parte das classes de coleções da plataforma .NET implementa, inclusive os arrays.
Objetivos
Aprendizado
Recursos usados
Preparando o ambiente - Criando o projeto no Visual Studio 2013
Abra o Visual Studio 2013 Express for Windows Desktop e clique em New Project;
Selecione o template Visual C# -> Windows -> Console Application e informe o nome LINQ_Objects_2 e clique em OK;
Com o projeto criado vamos incluir duas classes na solução :
No menu PROJECT clique em Add Class e informe o nome Contato.vb e a seguir inclua o seguinte código nesta classe:
Public Class Contato Public Property Nome() As String Public Shared Function DadosTeste() As List(Of Contato) |
Na classe Contato declaramos 6 propriedades e definimos os dados para uma coleção de objetos do tipo Contato a ser criada em memória.
A seguir, menu PROJECT clique em Add Class e informe o nome LogChamadas.vb e a seguir inclua o seguinte código nesta classe:
Public Class LogChamadas
Public Property Numero() As String
Public Property Duracao() As Integer
Public Property Recebida() As Boolean
Public Property Data() As DateTime
Public Shared Function DadosTeste() As List(Of LogChamadas)
Return New List(Of LogChamadas)() From { _
New LogChamadas() With { _
.Numero = "9553 8487", _
.Duracao = 2, _
.Recebida = True, _
.Data = New DateTime(2014, 8, 7, 8, 12, 0) _
}, _
New LogChamadas() With { _
.Numero = "8999 1154", _
.Duracao = 15, _
.Recebida = True, _
.Data = New DateTime(2014, 8, 7, 9, 23, 0) _
}, _
New LogChamadas() With { _
.Numero = "9602 6774", _
.Duracao = 1, _
.Recebida = False, _
.Data = New DateTime(2014, 8, 7, 10, 5, 0) _
}, _
New LogChamadas() With { _
.Numero = "8303 6030", _
.Duracao = 2, _
.Recebida = False, _
.Data = New DateTime(2014, 8, 7, 10, 35, 0) _
}, _
New LogChamadas() With { _
.Numero = "9907 5462", _
.Duracao = 4, _
.Recebida = True, _
.Data = New DateTime(2014, 8, 7, 11, 15, 0) _
}, _
New LogChamadas() With { _
.Numero = "9553 8487", _
.Duracao = 15, _
.Recebida = False, _
.Data = New DateTime(2014, 8, 7, 13, 12, 0) _
}, _
New LogChamadas() With { _
.Numero = "9553 8487", _
.Duracao = 3, _
.Recebida = True, _
.Data = New DateTime(2014, 8, 7, 13, 47, 0) _
}, _
New LogChamadas() With { _
.Numero = "9907 5462", _
.Duracao = 1, _
.Recebida = False, _
.Data = New DateTime(2014, 8, 7, 20, 34, 0) _
}, _
New LogChamadas() With { _
.Numero = "9907 5462", _
.Duracao = 3, _
.Recebida = False, _
.Data = New DateTime(2014, 8, 8, 10, 10, 0) _
}, _
New LogChamadas() With { _
.Numero = "8303 6030", _
.Duracao = 23, _
.Recebida = False, _
.Data = New DateTime(2014, 8, 8, 10, 40, 0) _
}, _
New LogChamadas() With { _
.Numero = "9918 2789", _
.Duracao = 3, _
.Recebida = False, _
.Data = New DateTime(2014, 8, 8, 14, 0, 0) _
}, _
New LogChamadas() With { _
.Numero = "9918 2789", _
.Duracao = 7, _
.Recebida = True, _
.Data = New DateTime(2014, 8, 8, 14, 37, 0) _
}, _
New LogChamadas() With { _
.Numero = "9902 3644", _
.Duracao = 6, _
.Recebida = True, _
.Data = New DateTime(2014, 8, 8, 15, 23, 0) _
}, _
New LogChamadas() With { _
.Numero = "9602 6774", _
.Duracao = 20, _
.Recebida = True, _
.Data = New DateTime(2014, 8, 8, 17, 12, 0) _
}, _
New LogChamadas() With { _
.Numero = "9553 8487", _
.Duracao = 5, _
.Recebida = True, _
.Data = New DateTime(2014, 7, 12, 8, 12, 0) _
}, _
New LogChamadas() With { _
.Numero = "8999 1154", _
.Duracao = 12, _
.Recebida = True, _
.Data = New DateTime(2014, 6, 14, 9, 23, 0) _
}, _
New LogChamadas() With { _
.Numero = "9602 6774", _
.Duracao = 10, _
.Recebida = False, _
.Data = New DateTime(2014, 7, 9, 10, 5, 0) _
}, _
New LogChamadas() With { _
.Numero = "8303 6030", _
.Duracao = 22, _
.Recebida = False, _
.Data = New DateTime(2014, 7, 5, 10, 35, 0) _
}, _
New LogChamadas() With { _
.Numero = "9907 5462", _
.Duracao = 9, _
.Recebida = True, _
.Data = New DateTime(2014, 6, 7, 11, 15, 0) _
}, _
New LogChamadas() With { _
.Numero = "9553 8487", _
.Duracao = 10, _
.Recebida = False, _
.Data = New DateTime(2014, 6, 7, 13, 12, 0) _
}, _
New LogChamadas() With { _
.Numero = "9553 8487", _
.Duracao = 21, _
.Recebida = True, _
.Data = New DateTime(2014, 7, 7, 13, 47, 0) _
}, _
New LogChamadas() With { _
.Numero = "9907 5462", _
.Duracao = 7, _
.Recebida = False, _
.Data = New DateTime(2014, 7, 7, 20, 34, 0) _
}, _
New LogChamadas() With { _
.Numero = "9907 5462", _
.Duracao = 2, _
.Recebida = False, _
.Data = New DateTime(2014, 6, 8, 10, 10, 0) _
}, _
New LogChamadas() With { _
.Numero = "8303 6030", _
.Duracao = 3, _
.Recebida = False, _
.Data = New DateTime(2014, 6, 8, 10, 40, 0) _
}, _
New LogChamadas() With { _
.Numero = "9918 2789", _
.Duracao = 32, _
.Recebida = False, _
.Data = New DateTime(2014, 7, 8, 14, 0, 0) _
}, _
New LogChamadas() With { _
.Numero = "9918 2789", _
.Duracao = 13, _
.Recebida = True, _
.Data = New DateTime(2014, 7, 8, 14, 37, 0) _
}, _
New LogChamadas() With { _
.Numero = "9902 3644", _
.Duracao = 16, _
.Recebida = True, _
.Data = New DateTime(2014, 5, 8, 15, 23, 0) _
}, _
New LogChamadas() With { _
.Numero = "9602 6774", _
.Duracao = 24, _
.Recebida = True, _
.Data = New DateTime(2014, 6, 8, 17, 12, 0) _
} _
}
End Function
End Class
|
Na classe LogChamadas declaramos 4 propriedades e definimos os dados para uma coleção de objetos do tipo LogChamadas a ser criada em memória que representa as ligações feitas pelos contatos. Existem portanto uma relação entre as duas classes que iremos usar para realizar a junção entre as coleções.
Consultando coleções de objetos
Vamos agora definir 4 consultas LINQ to Objects para mostrar como podemos obter informações de coleções.
No arquivo Module1.vb da nossa solução vamos declarar a chamada para 4 métodos que serão criados posteriormente conforme o código a seguir:
Sub Main()
Exemplo1()
'Exemplo2()
'Exemplo3()
'Exemplo4()
End Sub
|
A seguir vamos criar um método que irá ser executado em todas as consultas e que irá criar um pequeno cabeçalho para identificar a consulta:
Public Sub cabecalho(texto As String)
Console.WriteLine("Macoratti .net")
Console.WriteLine("--------------------------------------------------")
Console.WriteLine(texto)
Console.WriteLine("--------------------------------------------------")
Console.WriteLine("")
End Sub
|
Vamos agora criar cada uma das consultas:
1- Retornando uma lista de contatos com idade inferior a 45 anos:
Public Sub Exemplo1()
cabecalho("Lista Contatos com idade inferior a 45 anos")
Dim contatos As List(Of Contato) = Contato.DadosTeste()
Dim q = From c In contatos Where c.Nascimento.AddYears(45) > DateTime.Now Order By c.Nascimento Descending
Select String.Format("{0} {1} , nascimento : {2}", c.Nome, c.Sobrenome, c.Nascimento.ToString("dd-MMM-yyyy"))
For Each s As String In q
Console.WriteLine(s)
Next
Console.ReadKey()
End Sub
|
|
Observe que na cláusula Select usamos o método String.Format() para formatar a saída a consulta.
2- Além de filtrar itens em uma coleção e projetar os resultados, a LINQ oferece a capacidade de agrupar os itens de coleta em qualquer forma que você precisar. Nesta consulta agrupamos os contatos por Estado de origem:
Public Sub Exemplo2()
cabecalho("Lista Contatos por Estado")
Dim contatos As List(Of Contato) = Contato.DadosTeste()
Dim consulta = From c In contatos Group c By c.Estado Into ContatosGrupo = Group
For Each grupo In consulta
Console.WriteLine("Estado : " + grupo.Estado)
For Each c In grupo.ContatosGrupo
Console.WriteLine(" {0} {1}", c.Nome, c.Sobrenome)
Next
Next
Console.ReadKey()
End Sub
|
|
3- Um aspecto fundamental no acesso aos dados relacionados é o conceito de junção dos dados relacionados.
Os Sistemas de banco de dados relacional (como o Microsoft SQL Server) têm um poderoso recursos para realizar junções que permitem escrever consultas contra dados normalizados, o que é um termo chique para a "não repetir os dados" por separar os dados entre várias tabelas vinculando-os com um valor comum.
A LINQ permite fazer a junção(join) de várias coleções de objetos em conjunto, utilizando a sintaxe similar à SQL, como vemos na consulta a seguir:
Public Sub Exemplo3()
cabecalho("Consulta com junção de duas Coleções com base no numero do telefone")
Dim contatos As List(Of Contato) = Contato.DadosTeste()
Dim chamadas As List(Of LogChamadas) = LogChamadas.DadosTeste()
Dim consulta = From ligacao In chamadas
Join contato In contatos On _
ligacao.Numero Equals contato.Telefone _
Select New With { _
contato.Nome, _
contato.Sobrenome, _
ligacao.Data, _
ligacao.Duracao _
}
For Each c In consulta
Console.WriteLine(" {0} – {1} {2} ({3} min)", c.Data.ToString("dd MMM HH:m"), c.Nome, c.Sobrenome, c.Duracao)
Next
Console.ReadKey()
End Sub
|
|
4- Para demonstrar o poder da LINQ to Objects a consulta a seguir totaliza os dados a partir de duas coleções em memória usando junções, agrupamentos e ainda os operadores agregados (SUM, COUNT, AVG, etc.) na cláusula Select :
Public Sub Exemplo4()
cabecalho("Resumo do log de ligações, filtrando, ordenando, agrupando, " & vbLf & _
"juntando e selecionando usando valores agregados")
Dim contatos As List(Of Contato) = Contato.DadosTeste()
Dim chamadas As List(Of LogChamadas) = LogChamadas.DadosTeste()
Dim consulta = From ligacao In chamadas
Where ligacao.Recebida = True
Group ligacao By ligacao.Numero Into lig = Group
Join contato In contatos On
Numero Equals contato.Telefone
Order By contato.Nome, contato.Sobrenome
Select New With { _
contato.Nome, _
contato.Sobrenome, _
.Conta = lig.Count(), _
.Media = lig.Average(Function(c) c.Duracao), _
.Total = lig.Sum(Function(c) c.Duracao) _
}
For Each ligacao In consulta
Console.WriteLine("{0} {1} - ligações: {2}, Tempo: {3} mins, Média: {4} mins ", _
ligacao.Nome, ligacao.Sobrenome, ligacao.Conta, ligacao.Total, Math.Round(ligacao.Media, 2))
Next
Console.ReadKey()
End Sub
|
|
Percebeu que de forma quase intuitiva criamos as consultas usando a sintaxe do LINQ to Objects em coleções de memórias.
Pegue o projeto completo aqui: LINQ_Objects_2.zip
João 3:21 Mas quem pratica a verdade vem para a luz, a fim de que seja manifesto que as suas obras são feitas em Deus. (disse Jesus)
Veja os
Destaques e novidades do SUPER DVD Visual Basic
(sempre atualizado) : clique e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
|
Gostou ?
Compartilhe no Facebook
Compartilhe no Twitter
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
LINQ - Usando os operadores SKIP, TAKE e LET - Macoratti ...