Como falamos de consultas de dados, naturalmente o LINQ oferece suporte a diversas fontes, porém existem algumas limitações as quais os desenvolvedores devem atentar-se. É importante entender qual tecnologia LINQ irá se adequar melhor à sua necessidade, pois embora a sintaxe seja muito semelhante, algumas funcionalidades ou recursos podem não estar disponíveis em todas as fontes de dados. Como resolver este tipo de problema? Falaremos sobre isto neste atigo!

Uma outra motivação que me levam a escrever este artigo é que encontramos informações pulverizadas sobre LINQ em varios locais da internet. Não quero criar uma referência definitiva, mas pelo menos um local aonde se possa analisar diferentes tecnologias de consulta LINQ em um único lugar.

Desmistificando o LINQ

O LINQ utiliza alguns algorimos e métodos simples, porém muito interessantes e que oferecem muitas possibilidades, pois são combinatórios. Estes algoritmos e métodos permitem que a linguagem de consulta seja intuitiva e o resultado obtido de fácil compreensão. Para uma leitura complementar e compreensão apurada sobre algoritmos e os métodos por detrás do LINQ, procure por "Monadic Parser Combinations", "Reactive Extensions", "Lambda Expressions", "Generics", "Functional Programming" e "Fluent Interfaces". Há vários links na bibliografia deste artigo.

LINQ to Objects

Funciona com todos os tipos de objeto que implementem a interface IEnumerable ou IEnumerable. Oferece uma gama robusta, bastante complexa e flexível de acesso e manipulação dos conjuntos de dados sem um provedor intermediándo os dados, como LINQ to SQL ou LINQ to Entities.

LINQ to SQL

Desenhado para suporte e integração com SQL Server, o LINQ to SQL é a maneira mais simples, rápida e direta para acessar objetos do SQL Server.

LINQ to Entities

O LINQ to Entities é batante completo e é uma formidável ferramenta para acesso unificado a diversas fontes de dados. Através do Entity Framework, o LINQ oferece um grande suporte ao modelo ORM, suportando sub-conjuntos de dados, hierarquias, e suporte a fontes de dados diferentes, como SQL Server, Oracle ou Access.

LINQ to XML

Esta versão do LINQ é uma forma muito confortável DOM através de consultas. Através do LINQ to XML passamos a um próximo nível em Xpath, pois a forma de navegação nos documentos funciona como se estivessemos navegando numa coleção ou outra forma de dados estruturados.

LINQ to DataSet

Uma vez que o DataSet está instanciado e contém o conjunto de dados, utilizar o LINQ to Dataset torna-se uma manceira estruturada e eficiente de acesso a estes dados. Não é necessário navegar entre objetos e objetos filhos com os métodos tradicionais, pois o suporte hierarquico do LINQ mais uma vez torna o acesso a dados bastante uniforme.

IEnumerable e IQueryable

Todo o LINQ gira em torno destas interfaces. Basicamente são as interaces de consulta e navegação em coleções, porém o IEnumerable é para consultas aonde todo o conjunto é conhecido e os dados estão todos a disposição, enquanto IQueriable tem recursos mais sofisticados como Lazy Load. Mais adiante explicaremos ambas as diferenças e darei exemplos de como ambos funcionam.

Elaborei um conjunto testado de exemplos de LINQ agrupados por tecnologia de consulta. Em alguns casos haverá redundância de exemplos com diferentes tecnologias, para exemplificar as diferenças ou semelhanças, ou ainda, consultas que podem ser compatíveis entre tecnologias LINQ, sem os exemplos duplicados. Nestes casos cabe ao leitor testar todas as alternativas possíveis partindo dos exemplos disponíveis, a partir dos exemplos já criados.

Teremos então alguns exemplos praticos e explicações distribuidos da seguinte maneira:

- 21 dicas de LINQ to Objects
- 21 dicas de LINQ to SQL
- 21 dicas de LINQ to Entities
- 21 dicas de LINQ to XML
- 21 dicas de LINQ to Dataset

Estas partes estao também sub-divididas por tópicos pertinentes a tecnologia.

LINQ to Objects

A construção dos fontes:

Utilizei como base o seguinte código C#, para inserir o código no corpo:

 void Main(string[] args)
{
    string[] pais = {"Carlos Mario","Joana Silvo","Jorge Carla","Bianca Guitera"};
    string[] alunos = {"José Mario","Armando Silvo","Toninha Carla","Frederico Guitera"};
    string[] materias = {"Matematica","Portugues","Inglês","História""Ciências"};
    //
    // Os exemplos vão ficar aqui
    // 
    Console.Write("Pressione qualquer tecla para continuar…");
    Console.Read();
}

Cenário: Vamos declarar tres arrays, como se segue:

string[] pais = {“Carlos Mario”,”Joana Silvo”,”Jorge Carla”,”Bianca Guitera”}
string[] alunos = {“José Mario”,”Armando Silvo”,”Toninha Carla”,”Frederico Guitera”}
string[] materias = {“Matematica”,”Portugues”,”Inglês”,”História”, “Ciências”}

A. Localizando dados

1. Selecionando os alunos

IEnumerable<string> ver = from al in alunos where al.Length > 0 select al;
foreach(string s in ver) Console.Write("Saída do exemplo 1:{0}\n", s);

2. Localizando o aluno pelo sobrenome

IEnumerable<string> ex2 = from al in alunos where al.IndexOf("Guiter") > 0 select al;
foreach (string s in ex2) Console.Write("Saída do exemplo 2:{0}\n", s);

3. Localizando o aluno por expressão regular

Regex rParser = new Regex("\\b[B,C]");
IEnumerable<string> ex3 = from al in alunos where rParser.Matches(al).Count > 0 select al;
foreach (string s in ex3) Console.Write("Saída do exemplo 3:{0}\n", s);

4. Localizando aluno pelo tamanho do sobrenome

IEnumerable<string> ex4 = from al in alunos where al.Substring(al.IndexOf(" ")+1).Length > select al;
foreach (string s in ex4) Console.Write("Saída do exemplo 4:{0}\n", s);

5. Desmembrando nome e sobrenome para diferentes linhas

IEnumerable<string> ex5 = from aluno in alunos from nome in aluno.Split() select nome;
foreach (string s in ex5) Console.Write("Saída do exemplo 5:{0}\n", s);

6. Localizando dados com base no valor de uma variável

string alunoPesquisa = "Silvo";
var ex6 = from aluno in alunos where aluno.IndexOf(alunoPesquisa) >= 0 select aluno;
foreach (string s in ex6) Console.Write("Saída do exemplo 6:{0}\n", s);

7. Criando variáveis de analise em tempo de execução

var ex7= from aluno in alunos let AL=aluno.ToUpper() where AL.StartsWith("J"select aluno;
foreach (string s in ex) Console.Write("Saída do exemplo 7:{0}\n", s);

8. Consultas projetadas

Aqui um comentário interessante é que a diferença entre esta consulta e uma subconsulta comum é que “select new” retorna um tipo anônimo, entao a variavel de retorno precisa ser do tipo anonima também, para evitar erros de compilação:

   var ex8 = from aluno in alunos                 
             from pai in pais             
             where aluno.Substring(aluno.IndexOf(" ")+1) == pai.Substring(pai.IndexOf(" ")+1)        
                      select new { aluno, pai};                                              
   foreach (var s in ex8) Console.Write("Saída do exemplo 8:{0}\n", s.ToString());

9. Tipos anônimos em consultas

O que vale aqui é mais a teoria do que o exemplo. Uma consulta projetada retorna um tipo anônimo como vimos no exemplo anterior. Utilizamos o anonimo porque consultas lineares retornam geralmente listas que implementam a IEnumerable ou IQueriable como veremos a seguir. O problema com as consultas projetadas como no exemplo anterior é que o compilador não identifica que tipo será retornado, logo o retorno é um IEnumerable. É possível fazer consultas projetadas em tipos concretos, como veremos mais adiante.

   var ex9a = from m in materias select materias; // Aqui ex9 é do tipo 
   var ex9b = from ... select new {x,y,z}; // Aqui ex9 é do tipo 

10. Utilizando a palavra chave INTO

    var ex10 = from a in alunos
           join p in pais
           on a.Substring(a.IndexOf(" ") + 1) equals p.Substring(p.IndexOf(" ") + 1)
           select a + "," + p
                  into familia
                  select familia;

    foreach (var s in ex10) Console.Write("Saída do exemplo 10:{0}\n", s);

Proxima parte do artigo:

No próximo artigo leremos mais sobre relacionamento de dados entre coleções e arrays, e também abordaremos o LINQ to SQL. Sugestões sao muito bem vindas. Mandem-me e-mails ou postem mensagens aqui no blog se tiverem sugestões.

Abraços!