.NET - Apresetando LINQ To SQL - III
"It's about turning query set operations and transforms into first-class concepts of the language"
Foi com esta frase que Anders Hejlsberg , o arquiteto chefe da linguagem C#, definiu o LINQ - Language Integrated Query.
A LINQ apresenta uma sintaxe usada nas linguagens funcionais como a linguagem SQL de forma a tornar mais intuitiva e simples o acesso aos dados.
O propósito deste artigo é expor uma visão geral do papel do LINQ To SQL e sua integração com banco de dados em aplicações Visual Basic. Vou mostrar como as classes são mapeadas para os banco de dados e como refinar o processo de mapeamento. Como a jornada é longa vamos por partes.
Material necessário:
1- Visual Basic 2008 Express Editon
ou Visual Studio 2008
2- Banco de dados Northwind.mdf
Criando um modelo de Objetos usando o descritor Visual LINQ
Podemos criar um modelo de objetos mapeados para o banco de dados via código mas usando o descritor Visual LINQ é tarefa é mais rápida e fácil. Então vamos a ela:
Criando um projeto Linq
- Abra o VB 2008 Express e clique no menu File|New Project;
A seguir selecione o template Windows Forms Application e informe o nome LINQ_SQL_VB1 e clique em OK;
Agora clique no menu Project|Add New Item (CTRL+Shift+A) e a seguir selecione LINQ to SQL Classes e informe o nome Northwind.dbml;
Agora dê uma espiada na janela Solution Explorer; clique no ícone Show all Files e você verá as referências para o assembly System.Data.Linq e o arquivo Northwind.dbml contendo o descritor LINQ e o código gerado no processo.
Abra o DataBase Explorer no menu View | DataBase Explorer e verifique se já existe uma conexão com o banco de dados Northwind. Se ela não existir clique com o botão direito do mouse sobre a o ícone Data Connections e selecione Add Connection. Selecione o Data Source - Microsoft SQL Server DataBase File e no botão Browse localize o banco de dados Northwind.mdf na sua máquina local.
Ao final do processo a sua janela DataBase Explorer deverá exibir a conexão com o Northwind.mdf exibindo os objetos do banco de dados conforme abaixo:
Expanda os objetos Tables, selecione e arraste para o descritor LINQ as seguintes tabelas: Customers, Orders e Employees.
Você verá no descritor LINQ as classes das entidades: Customer, Order e Employee geradas e se clicar no arquivo Northwind.designer.vb verá o código gerado pelo mesmo.
Agora expanda os objetos Stored Procedures na janela DataBase Explorer e selecione a stored procedure Ten Most Expensive Products e arraste para a janela Methods do Descritor LINQ (Se não estiver visualizando a janela, clique com o botão direito sobre o descritor e selecione Show Methods Pane)
A Stored Procedure Ten Most Expensive Products possui o seguinte código:
SELECT Products.ProductName AS TenMostExpensiveProducts, Products.UnitPrice FROM Products ORDER BY Products.UnitPrice DESC |
Ela selecione o nome do produto e o preço unitário da tabela Products e ordena por preço unitário em ordem decrescente.
Vamos agora criar a interface no formulário form1.vb com dois ListBox e um botão de comando conforme leiaute abaixo:
No evento Click do botão de comando Executar vamos inserir o código abaixo:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'instanciamos a classe DataContext que já tem mapeado os objetos e a conexão Dim db As New NorthwindDataContext 'selecione os clientes de Londres Dim clientes = From customer In db.Customers _ Where customer.City = "London" _ Select customer 'cabeçalho do ListBox1 ListBox1.Items.Add("Clientes de Londres") ListBox1.Items.Add("-------------------------") ListBox1.Items.Add("Cliente - Total") ListBox1.Items.Add("-------------------------") 'exibe os clientes de Londres e o total de clientes For Each cliente In clientes ListBox1.Items.Add(cliente.CustomerID & " - " & cliente.Orders.Count) Next 'cabeçalho do ListBox2 ListBox2.Items.Add("Os dez produtos mais vendidos") ListBox2.Items.Add("----------------------------------") ListBox2.Items.Add("Nome do Produto - Preço Unitário") ListBox2.Items.Add("----------------------------------") 'exibe o nome do produto e o preço unitário For Each produto In db.Ten_Most_Expensive_Products ListBox2.Items.Add(produto.TenMostExpensiveProducts & " / " & produto.UnitPrice) Next End Sub |
Ao digitar o código você vai perceber que o recurso IntelliSense exibirá os mapeamentos para os objetos. Você verá o mapeamento para a stored procedure Ten_Most_Expensive_Products como um método DataContext. Verá também que o descritor criou o tipo Ten_Most_Expensive_Products contendo duas propriedades mapeadas para os campos retornadas pela stored procedure.
Executando o projeto iremos obter:
Vamos examinar o código:
Comecemos com a declaração:
'instanciamos a
classe DataContext que já tem mapeado os objetos e a conexão
Dim db As New NorthwindDataContext
Este código cria um objeto NorthwindDataContext
que representa uma conexão fortemente tipada com o banco de
dados. O nome NorthwindDataContext é baseado no nome informado
para o arquivo .dbml acrescentando a palavra DataContext ao final
do mesmo.
Examinando a instrução LINQ:
'selecione os
clientes de Londres
Dim
clientes = From customer In db.Customers _
Where
customer.City = "London" _
Select
customer
iremos perceber que do lado esquerdo da atribuição estamos declarando uma variável chamada clientes sem tipo definido.
Isto é possível devido a uma das novas características da plataforma .NET 3.5 : Inferência de tipos, onde a informação de tipo será , quando possível, inferida diretamente pelo compilador.
O lado direito da atribuição temos uma expressão de consulta que é uma extensão da linguagem introduzida pelo projeto LINQ. A inferência de tipos esta sendo usada aqui para simplificar o código.
A inferência de tipos também é usada no comando For/Each pois não estamos especificando um tipo para a variável cliente.
'exibe os clientes
de Londres e o total de clientes
For Each cliente In clientes
ListBox1.Items.Add(cliente.CustomerID
& " - " & cliente.Orders.Count)
Next
Observe que o total de clientes é obtido pelo LINQ atráves do código: cliente.Orders.Count
No código abaixo:
'exibe o nome do
produto e o preço unitário
For Each produto In db.Ten_Most_Expensive_Products
ListBox2.Items.Add(produto.TenMostExpensiveProducts
& " / " & produto.UnitPrice)
Next
Temos o método Ten_Most_Expensive_Products
mapeado da stored procedure Ten Most Expensive Products.
Agregando Dados usando os operadores do LINQ
Podemos facilmente usar os operadores de consulta LINQ para realizar consultas de dados agregados. Para poder realizar as consultas a seguir volte a janela DataBase Explorer e arraste a tabela Products para o descrito LINQ para gerar o mapeamento para a classe da entidade Product.
A seguir vamos incluir um novo ListBox no formulário e um botão de comando. A seguir inclua o código abaixo no evento Click do botão de comando:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click 'instanciamos a classe DataContext que já tem mapeado os objetos e a conexão Dim db As New NorthwindDataContext 'calcula o custo médio dos produtos com letra inicial B Dim custoMedio = Aggregate produto In db.Products _ Where produto.ProductName.StartsWith("B") _ Select produto.UnitPrice _ Into Average() 'cabeçalho do ListBox3 ListBox3.Items.Add("Produtos que iniciam com a letra B") ListBox3.Items.Add("------------------------------------") ListBox3.Items.Add(" Custo médio = " & custoMedio) End Sub |
Pressionando F5 para executar iremos obter:
Vamos examinar a instrução LINQ:
Dim custoMedio = Aggregate
produto In db.Products _
Where
produto.ProductName.StartsWith("B") _
Select
produto.UnitPrice _
Into
Average()
O resultado obtido será o custo
médio dos produtos iniciados com a letra "B".
Primeiro especificamos a tabela db.Products e
restringimos a seleção às linhas com produtos cujo nome
iniciam com "B".
Ao conjunto de registros obtido aplicamos dois operadores: (Select)
onde Selecionamos a coluna UnitPrice , obtendo
assim uma coleção de de preços em seguida ; e usando o
operador Average() , calculamos a média sobre a
coleção de preços retornando um único valor.
Referências:
José Carlos Macoratti