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
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
var ex9a = from m in materias select materias; // Aqui ex9 é do tipovar 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!