O documento discute o uso de LINQ (Language Integrated Query) no C# para manipular dados. É introduzido o conceito de LINQ, suas vantagens e como funciona. Em seguida, são apresentados exemplos de consultas LINQ usando diferentes fontes de dados, como arrays, coleções e bancos de dados SQL.
2. Introdução ao LINQ
Inferência de Tipos
Tipos Anônimos
Expressões Lambda
Métodos de Extensão
LINQ to SQL: Introdução
LINQ to SQL: Integração com o Visual Studio
LINQ Providers
29/03/2015LINQ via C# - .Net Coders 2
3. O que é LINQ?
Language Integrated Query
Biblioteca de consulta a dados
Incorporado ao .Net Framework 3.5, lançado com a versão 3.0 do C#
Por que LINQ é necessário?
Permite ao desenvolvedor criar expressões de consulta em qualquer fonte de dados
Sintaxe prática e enxuta
Escrever menos código facilita a manipulação de dados
29/03/2015LINQ via C# - .Net Coders 3
4. Uma query (ou consulta) é uma expressão que extrai dados de uma fonte de dados
Geralmente, as queries são escritas com uma linguagem específica para cada fonte
de dados. Ex: SQL para BDs relacionais e XQuery para XML.
Não é vantajoso para o desenvolvedor ter de aprender uma linguagem nova para
cada fonte de dados
É aí que entra o LINQ que fornece um modelo unificado (e simplificado) para
manipular dados com o .Net
29/03/2015LINQ via C# - .Net Coders 4
5. Escrevendo a primeira query – LINQ to Objects
Uma query LINQ consiste de 3 operações distintas:
1. Obter o data source (fonte de dados)
2. Criar a query
3. Executar a query
29/03/2015LINQ via C# - .Net Coders 5
7. A fonte de dados neste exemplo é um array de inteiros
Dois lados da query: o lado esquerdo (atribuição) e o lado direito (filtro)
Note que para fazer um filtro não basta apenas criar uma variável.
Construindo o filtro:
Começa com a palavra-chave ‘from’
Crie uma variável (num) que referencia os elementos da fonte de dados
Especifique a fonte de dados (in arrNums)
O ‘where’ aplica alguma condição específica, embora não seja necessário
O ‘select’ seleciona os elementos filtrados
Um laço (foreach) irá iterar sobre o lado direito da query para imprimir seu
resultado
29/03/2015LINQ via C# - .Net Coders 7
8. Para ser possível a iteração sobre os elementos de uma fonte de dados, é necessário
que essa classe implemente a interface IEnumerable<T>. Os tipos primitivos do .Net
Framework já implementam por padrão essa interface.
Então, a query é executada dentro de um foreach.
29/03/2015LINQ via C# - .Net Coders 8
9. IEnumerable<T> e Generics
As consultas LINQ são baseadas em Generics
Dois conceitos-chave:
Quando você cria uma instância de uma classe genérica, você substitui o ‘T’ pelo tipo instanciado.
Por exemplo, ao criar uma List de string, o ‘T’ é substituído por ‘string’.
A interface genérica IEnumerable<T> permite a iteração sobre elementos de classes que a
implementam
29/03/2015LINQ via C# - .Net Coders 9
10. Neste exemplo, é criada uma lista de Pessoas e a query seleciona todas as pessoas;
O tipo retornado pela consulta é um IEnumerable<Pessoa>
29/03/2015LINQ via C# - .Net Coders 10
11. É possível “omitir” a notação genérica pelo uso da palavra-chave var;
Ao referenciar uma variável com ‘var’ o compilador infere, ou seja, resolve em
tempo de compilação o tipo daquela variável.
No exemplo a seguir será feito um filtro de pessoas do sexo feminino:
29/03/2015LINQ via C# - .Net Coders 11
13. Regras de utilização:
Erros de compilação:
Declarar uma variável com var e não atribuir nenhum valor
Atribuir null a uma variável var
Declarar um atributo como var (use-o somente como variável local)
Recomenda-se usar var quando:
Queries LINQ
Tipos por referência
29/03/2015LINQ via C# - .Net Coders 13
15. É um recurso para encapsular propriedades a um objeto sem ter de criar um novo
tipo (uma nova classe) para isso;
O nome do tipo é gerado pelo compilador e o tipo de suas propriedades é inferido
por ele;
O tipo não é acessível no código-fonte;
As propriedades de um tipo anônimo são read-only
Não podem ser usados como atributos;
Um tipo anônimo é definido sempre com a palavra-chave var;
29/03/2015LINQ via C# - .Net Coders 15
16. Como criar um tipo anônimo:
Perceba que as propriedades de um tipo anônimo são imutáveis. Não é possível a
escrita (set).
29/03/2015LINQ via C# - .Net Coders 16
17. Exemplo de utilização: projeções em expressões LINQ
O que é uma projeção?
A cláusula select pode ser utilizada para retornar um subconjunto específico das
propriedades de cada objeto na fonte de dados muitas vezes diferente dos dados originais
Útil quando você quer guardar algumas informações de cada objeto em uma sequência
Select new {...};
29/03/2015LINQ via C# - .Net Coders 17
18. Exemplo: selecionar alunos com as maiores notas da turma (maior ou igual a 7)
29/03/2015LINQ via C# - .Net Coders 18
19. Exemplo: selecionar alunos que possuem uma dependência em Álgebra Linear
29/03/2015LINQ via C# - .Net Coders 19
20. Uma expressão lambda é uma função anônima com a qual é possível criar delegates
ou árvores de expressão
Você pode usar uma expressão lambda como uma função local e passar argumentos
ou retornar valores de funções
Muito útil para escrever consultas LINQ
Primeiro exemplo: lambda com delegate
29/03/2015LINQ via C# - .Net Coders 20
21. Os delegates são definidos em uma outra classe. Ou, se estiver usando no Main,
defina-o fora dele:
Outro exemplo
29/03/2015LINQ via C# - .Net Coders 21
22. Delegates funcionam como referências a métodos e são base para criar eventos no
.Net. São como protótipos de funções (C/C++) inclusive.
Nos exemplos anteriores, foi definido utilizando uma expressão lambda o delegate
para multiplicar um número por ele mesmo. E depois, em uma variável armazena-se
o resultado da chamada do delegate.
Para criar uma expressão lambda você lista parâmetros de entrada (caso tenha) no
lado esquerdo do operador =>, e a expressão em si (o filtro) fica do lado direito.
Ex.: A expressão x => x * x especifica o parâmetro x que armazena o retorno de x * x.
Ex2: A expressão (x,y) => x – y especifica dois parâmetros x e y para ser realizada uma
subtração. Os argumentos nesta chamada, segundo o exemplo anterior, são 10 e 5 (em
subtrairDelegate(10,5))
29/03/2015LINQ via C# - .Net Coders 22
23. Utilizando o mesmo array do primeiro exemplo, faremos uma expressão lambda para
retornar os números ímpares deste array:
Perceba que a expressão fica bem mais enxuta em comparação às demais. O filtro é
feito por meio do método de extensão Where.
29/03/2015LINQ via C# - .Net Coders 23
24. Na versão 3.0 do C# foi introduzida uma nova feature chamada métodos de
extensão, que permite ao desenvolvedor acrescentar novos métodos em classes
existentes sem ter de utilizar os recursos de herança, ou até implementar alguma
modificação no arquivo original.
Como funciona? Os métodos de extensão são definidos como estáticos (em classes
também estáticas), mas são chamados como os métodos de instância.
Ex.: criamos uma classe chamada MyExtensions e definimos nela um método ToURL, que
transforma uma string qualquer em uma URL:
29/03/2015LINQ via C# - .Net Coders 24
25. O que acontece, na verdade, é que estamos adicionando um método à classe String
do .Net. Para isso funcionar, basta escrever ‘this’ no parâmetro antes do nome da
classe, como mostra o slide anterior.
Uma observação é que o IntelliSense identifica um método de extensão pela seta
azul ao lado do nome do método. Podemos ver que os métodos do LINQ que
utilizamos no dia a dia são de extensão, definidos na classe Enumerable.
29/03/2015LINQ via C# - .Net Coders 25
26. Apresentando outros métodos de extensão
Average: retorna a média dos valores em uma coleção
ElementAt: retorna o elemento em determinada posição
29/03/2015LINQ via C# - .Net Coders 26
27. ElementAtOrDefault: retorna o elemento em determinada posição, ou null, caso a posição
seja inválida.
OrderBy, GroupBy:
Crie a classe Funcionario:
29/03/2015LINQ via C# - .Net Coders 27
28. Instancie 10 objetos da classe Funcionario e popule suas propriedades:
Crie uma lista de Funcionários, inicializando-a com esses objetos:
29/03/2015LINQ via C# - .Net Coders 28
29. GroupBy (com e sem o método de extensão)
Selecionamos os salários de funcionários em ordem crescente (default)
Quando é ordem crescente não é necessário escrever ascending
Em ordem decrescente: orderby (expressão) descending
29/03/2015LINQ via C# - .Net Coders 29
30. Aplicando o LIKE do SQL
Selecionar funcionárias que contenham “ita” no nome
29/03/2015LINQ via C# - .Net Coders 30
31. Agrupar funcionários por departamento
group (elementos) by (chave de agrupamento) into (variável de agrupamento)
Faça uma projeção definindo um tipo anônimo para retornar os dados filtrados (select new)
No exemplo será impresso o departamento e o total de funcionários por depto.
29/03/2015LINQ via C# - .Net Coders 31
32. Agrupar funcionários por departamento
group (elementos) by (chave de agrupamento) into (variável de agrupamento)
Faça uma projeção definindo um tipo anônimo para retornar os dados filtrados (select new)
No exemplo será impresso o departamento e o total de funcionários por depto.
29/03/2015LINQ via C# - .Net Coders 32
33. Exemplo de uma consulta sem LINQ
Exemplo de uma consulta com LINQ
29/03/2015LINQ via C# - .Net Coders 33
34. Nessa parte iremos demonstrar como utilizar consultas LINQ para manipular uma base de
dados SQL Server.
Para isso, tenha instalado o SQL Server Management Studio 2008 ou superior.
29/03/2015LINQ via C# - .Net Coders 34
35. Estudo de caso: Apresentar em um gridview todos os filmes cadastrados em uma locadora
Conecte ao SQL Server;
Criação da Base de Dados
No Object Explorer, clique com o botão direito sobre a pasta Databases e escolha “New Database”
Caso não esteja visível, no Menu acima clique em View e depois escolhe a opção Object Explorer
Em Database Name digite: ProducoesArtisticas e depois confirme.
Selecione agora o banco ProducoesArtisticas, expanda-o no nível de pastas, e selecione a pasta
Tables. Com o botão direito, clique em “New Table”
Crie a tabela “Filmes” com os campos FilmeID (int), Nome (varchar (50)), Ano (datetime), Preço
(decimal (10,2)), Genero (varchar(15)).
Crie a tabela “Atores” com os campos AtorID (int), FilmeID (int), Nome (varchar (40))
Defina a chave primária de cada tabela: Filmes: FilmeID / Atores: AtorID (Set Primary Key...)
29/03/2015LINQ via C# - .Net Coders 35
36. Defina o incremento automático de inserção de registros na tabela
A cada registro inserido, o ID será incrementado de 1 em 1 ou conforme for editado em “Identity
Increment”
29/03/2015LINQ via C# - .Net Coders 36
37. Relacionamento entre tabelas
Pode ser feito via diagrama relacional ou manualmente por uma query
Via diagrama relacional:
Na pasta Database Diagrams, confirme a criação de um novo diagrama
Selecione as duas tabelas e clique em Add
Faça a ligação entre as duas tabelas, puxando uma seta do campo FilmeID da tabela Filmes para
o campo FilmeID da tabela Atores.
Feito isso, abrirá uma janela “Tables and Columns”. Defina o nome do relacionamento como
FK_Atores_Filmes (atores que participaram de um filme).
Primary Key table: Filmes / Foreign Key table: Atores (campos FilmeID)
Via query: (cria-se uma referência de Filme na tabela de Atores)
29/03/2015LINQ via C# - .Net Coders 37
38. Crie um projeto do tipo Console Application com o nome: NetCoders.LINQtoSQL.Intro;
Abra a janela Server Explorer (Menu -> View -> Server Explorer) para configurar a conexão
com o banco;
Com o botão direito clique em Data Connections -> Add Connection;
Mude o Data Source de “Microsoft SQL Server Database File (SqlClient)” para “Microsoft
SQL Server”;
Escolha o seu servidor e a opção de login (Windows Authentication ou SQL Server
Authentication);
Selecione o banco de dados ProducoesArtisticas;
Concluído o processo de configuração, a sua conexão deverá estar visível em Data
Connections.
29/03/2015LINQ via C# - .Net Coders 38
39. Inserção de registros: pode ser via SQL Server ou pelo Visual Studio
Via SQL Server:
Popule a tabela de Filmes, depois a tabela de Atores:
Filmes
29/03/2015LINQ via C# - .Net Coders 39
40. Atores
Verificar na tabela de Filmes qual é o ID do Filme no qual esse ator esteve presente
Exemplo: Robbie Williams – Uma Noite no Museu 3 (FilmeID = 3)
Tom Cruise – Mission Impossible (FilmeID = 4), etc...
29/03/2015LINQ via C# - .Net Coders 40
41. Fazendo a junção (join) entre as tabelas Filmes e Atores, é possível reunir esta
informação:
E o resultado será este:
29/03/2015LINQ via C# - .Net Coders 41
42. As classes DataContext definidos no namespace System.Linq implementam os métodos que
permitem a aplicação interagir com os dados salvos no banco;
Essas classes podem ser automaticamente geradas pelo Visual Studio:
No Solution Explorer, clique com o botão direito sobre o projeto
Escolha a opção Add New Item e depois “LINQ to SQL Classes”
Guarde o modelo como ProducoesArtisticas
Arraste as tabelas do Server Explorer para a tela do desenho do modelo de dados, para obter um
diagrama como esse:
29/03/2015LINQ via C# - .Net Coders 42
43. A partir do momento em que arrastamos as tabelas o Visual Studio realiza o mapeamento
do banco de dados para a aplicação automaticamente
Verifique o código mapeado em ProducoesArtisticas.designer.cs
Fazer uma consulta LINQ acessando a base de dados SQL Server:
Instancie o modelo:
Agrupar os filmes por gênero
29/03/2015LINQ via C# - .Net Coders 43
44. Como resultado, percebe-se que as aplicações Console nem sempre são as melhores para a
apresentação de dados para o usuário;
Então, crie um projeto Windows Forms com o nome: NetCoders.LINQtoSQL
Set as Startup Project...
Repita o mesmo procedimento dos slides anteriores para mapear o BD na aplicação
No Form1.cs[Design], arraste um DataGridView da ToolBox;
Name: dgFilmes
Form1_Load: duplo clique no form para gerar este evento
Neste evento, quando a aplicação for carregada, ela carregará o grid populado com os dados do
banco
29/03/2015LINQ via C# - .Net Coders 44
45. Form1_Load:
Criação das colunas do grid
Instanciar o contexto
Aplicar a query: selecionar todos os filmes cadastrados
29/03/2015LINQ via C# - .Net Coders 45
46. Form1_Load:
Cria uma variável idLinha que representa cada linha na tabela
Dentro do foreach, preenchemos a tabela:
29/03/2015LINQ via C# - .Net Coders 46
48. Fazer uma consulta LINQ to SQL com que realize uma junção das tabelas Atores e Filmes
Selecionar atores que tenham participado de algum filme
Modifique o foreach para imprimir o nome do ator e o nome do filme:
29/03/2015LINQ via C# - .Net Coders 48
49. Fazer uma consulta LINQ to SQL com que realize uma junção das tabelas Atores e Filmes
Modifique as colunas..
Resultado:
29/03/2015LINQ via C# - .Net Coders 49
50. Um LINQ Provider é uma implementação do “padrão LINQ” para uma fonte de dados
específica;
O padrão LINQ define um conjunto de regras que explicita como os comandos LINQ
são mapeados em invocações de métodos de um determinado tipo.
Nem sempre o próprio tipo introduz esses métodos; eles são definidos por meio de
um Provider adaptado a implementar os métodos de extensão.
Ao longo dessa palestra, apresentamos o LINQ to Objects, com o qual é possível
fazer consultas a coleções de dados em memória; e o LINQ to SQL, para fazer
consulta a uma base de dados SQL.
29/03/2015LINQ via C# - .Net Coders 50
51. Esses são os LINQ Providers implementados no .Net Framework:
29/03/2015LINQ via C# - .Net Coders 51
52. Ponto de partida: a interface IEnumerable<T>
Ela fornece o método GetEnumerator() que permite a iteração entre os elementos de uma
coleção.
Estratégias para expandir o LINQ para outras fontes de dados não mapeadas pelo
.Net:
Adaptar uma API existente, definindo novas classes que podem ser usadas com os Providers
LINQ existentes
Criar um novo conjunto de classes para permitir a reutilização dos métodos de extensão
Escrever um Provider LINQ capaz de trabalhar com árvores de expressões
Utilizado para converter código LINQ para outra linguagem
Outra estratégia é escrever em determinada classe novos métodos de extensão que
realizam operações auxiliares (mais simples).
29/03/2015LINQ via C# - .Net Coders 52
53. Um LINQ Provider deve implementar métodos como Select, Where, Join, OrderBy
(dentre outros) em uma classe genérica.
29/03/2015LINQ via C# - .Net Coders 53
54. Vantagens
Sintaxe unificada de acesso a dados (desde que haja um provider que implemente o padrão
LINQ sobre essa fonte de dados);
Utilização simultânea de vários Providers: uma mesma expressão pode ter dados de várias
fontes de dados;
Consultas fortemente tipadas: todas as expressões são compiladas, assim todos os possíveis
erros são detectados em tempo de compilação;
Fácil extensão: caso queira uma nova fonte de dados interagir com LINQ, basta
implementar um provider com os métodos definidos pelo LINQ;
Padronização, código limpo e de fácil manutenção
29/03/2015LINQ via C# - .Net Coders 39
55. Desvantagens
Queries maiores em SQL no LINQ acaba gerando um código menos performático
Curva de aprendizado para aprender LINQ
29/03/2015LINQ via C# - .Net Coders 40