Вы находитесь на странице: 1из 20

VB .NET Tradutor Multilngue baseado no Google Translate (OSSkin.

Net)
sexta-feira, 20/05/2011 s 10h05, por Jos Carlos Macoratti Adicione o recurso da traduo ao seus programas VB.NET. Use o tradutor de sites do Google em seus programas e oferea acesso instantneo a tradues automticas. Comece informando o texto a traduzir, depois escolha o idioma de destino para a traduo e pronto! Seu texto ser traduzido usando o Google Translate.

O projeto Visual Basic usa os controle WebBrowser, ProgressBar, ToolStip, NotifyIcon e ContextMenu. A aplicao tambm usa o componente OSSkin.Net que permite utilizar Skins em aplicaes .NET. O componente OSSkin.Net permite que os desenvolvedores usem o recurso de skins em aplicaes Windows Forms na plataforma .NET a partir de uma escolha de 18 estilos, incluindo Windows XP, Vista, o Aero, Office 2007 e temas Mac OS-X. Graas aos recursos avanados concebidos inteiramente em C#, ele o nico produto disponvel atualmente que permite mudar completamente a aparncia de todas as formas de janelas,formulrios, controles e dilogos. O cdigo da aplicao trivial, veja abaixo o exemplo da chamada para a converso Ingls -> Portugus:

WebBrowser1.Navigate(http://translate.google.com/#en|pt| & TextBox1.Text)

Pegue o projeto completo: TradutorGoogle.zip Simples assim! Eu sei, apenas VB .NET, mas eu gosto

VB .NET Atualizando tabelas relacionadas com ADO .NET Parte 01


Este artigo faz uma reviso dos conceitos da tecnologia ADO .NET atravs de um exemplo prtico. Vamos partir de um modelo de dados simples e que j esta pronto para uso, dessa forma vamos usar o banco de dados Northwind.mdf. Este banco de dados possui diversas tabelas relacionadas, mas nosso interesse estar focado nas tabelas: Orders, Orders Details, Suppliers, Products, Customers e Employees. Abaixo vemos o relacionamento existente entre essas tabelas:

Nosso objetivo ser atualizar as tabelas Orders e Orders Details com informaes obtidas de um formulrio que simular o envio de um pedido e seus detalhes. Embora as demais tabelas no sejam atualizadas, iremos precisar de suas informaes. Neste artigo eu vou mostrar como realizar esta tarefa usando ADO .NET e seus objetos; e na segunda parte irei mostrar como fica a mesma tarefa sendo realizada com os recursos do LINQ to SQL. Alm de revisarmos os conceitos relacionados com os objetos bsicos da ADO .NET, como DataReader, DataAdapter e SqlCommand. Iremos trabalhar com classes, transaes e instrues SQL parametrizadas. Como temos o modelo de dados j pronto, eu vou iniciar mostrando como ser o formulrio de entrada de dados usado na aplicao. Os recursos necessrios para acompanhar este artigo so:

Visual Basic 2010 Express Edition SQL Server 2008 Express Banco de dados Northwind.mdf

Criando o projeto e definindo as classes do domnio


Abra o Visual Basic 2010 Express Edition e crie um novo projeto do tipo Windows Forms Application> com o nome NW_Pedidos. Altere o nome do formulrio padro para frmSQL.vb e inclua os seguintes controles a partir da ToolBox no formulrio:

2 Combobox cboClientes e cboFuncionarios 5 TextBox txtID, txtProduto (ReadOnly=True), txtPreco (ReadOnly=True), txtQtde, txtSubtotal (ReadOnly=True) 2 ListView ListView1 e ListView2 2 TextBox txtItems e txtTotal 4 TextBox txtNome, txtEndereco, txtCidade e txtRegiao 2 Buttons btnSalvar e btnNovo

Os dois controles Combobox devero ser preenchidos quando o formulrio for carregado, permitindo que o usurio selecione o cliente e o funcionrio. A seguir, o usurio dever informar o cdigo do produto e, ao teclar ENTER, ser realizada uma busca e o nome do produto e seu preo unitrio ser exibido, bastando ao usurio informar a quantidade desejada para que o valor total seja calculado e o novo pedido exibido no controle ListView.

A seguir, o usurio deve informar os dados do destinatrio: Nome, Endereo, Cidade e Regio e clicar no boto Salvar Pedido para persistir os dados do novo pedido e seus detalhes. Este cenrio muito frequente em aplicaes comerciais. Vamos, ento, mostrar como implementar o cdigo das funcionalidades envolvidas nesta operao.

1. Definindo as classes do domnio


Vamos definir as classes Products, Employees, Customers, Orders e Orders Details.

Classe NWProduto
No menu Project, clique em Add Class e selecione o template Class informando o nome NWProduto:

Digite o cdigo abaixo na classe NWProdutos; nele estamos definindo trs variveis com o mesmo nome dos campos da tabela Products e o mtodo getProdutoPorId() que retorna uma lista de produtos:
Public Class NWProduto Public ProductID As Integer Public ProductName As String Public ProductPrice As Decimal Public Shared Function getProdutoPorId(ByVal productID As String) As List(Of NWProduto) Dim produtos As New List(Of NWProduto) Dim CN As New SqlClient.SqlConnection(strConexao) Dim CMD As New SqlClient.SqlCommand Dim RDR As SqlClient.SqlDataReader If IsNumeric(productID) Then CMD.CommandText = "SELECT * FROM products WHERE ProductID=@ProductID" CMD.CommandType = CommandType.Text CMD.Parameters.AddWithValue("@ProductID", productID) CMD.Connection = CN CN.Open() RDR = CMD.ExecuteReader Dim prod As NWProduto = Nothing If RDR.Read Then prod = New NWProduto prod.ProductID = RDR.GetInt32(RDR.GetOrdinal("ProductID")) prod.ProductName = RDR.GetString(RDR.GetOrdinal("ProductName")) prod.ProductPrice = RDR.GetDecimal(RDR.GetOrdinal("UnitPrice")) produtos.Add(prod) End If Else CMD.CommandText = "SELECT * FROM Products WHERE ProductName LIKE '%' + @ProductID + '%'" CMD.CommandType = CommandType.Text CMD.Parameters.AddWithValue("@ProductID", productID) CMD.Connection = CN CN.Open() RDR = CMD.ExecuteReader While RDR.Read Dim prod As New NWProduto prod.ProductID = RDR.GetInt32(RDR.GetOrdinal("ProductID")) prod.ProductName = RDR.GetString(RDR.GetOrdinal("ProductName")) prod.ProductPrice = RDR.GetDecimal(RDR.GetOrdinal("UnitPrice")) produtos.Add(prod) End While End If CN.Close() Return produtos End Function

End Class

O mtodo getProdutoPorID retorna uma lista de produtos pelo cdigo informado.

Classe NWFuncionario
Repita o procedimento feito para criar a classe NWProduto e crie a classe NWFuncionario. Nesta classe definimos duas variveis, o mtodo GetTodosFuncionarios(), que retorna uma lista de funcionrios, e sobrescrevemos o mtodo ToString() que agora retorna o nome do funcionrio.
Public Class NWFuncionario Public EmployeeID As Integer Public EmployeeName As String Public Overrides Function ToString() As String Return EmployeeName End Function Public Shared Function GetTodosFuncionarios() As List(Of NWFuncionario) Dim CMD As New SqlClient.SqlCommand Dim Funcionarios As New List(Of NWFuncionario) CMD.CommandText = "SELECT * FROM Employees" CMD.CommandType = CommandType.Text Dim CN As New SqlClient.SqlConnection(strConexao) CMD.Connection = CN CN.Open() Dim RDR As SqlClient.SqlDataReader RDR = CMD.ExecuteReader() While RDR.Read Dim Emp As New NWFuncionario Emp.EmployeeID = RDR.GetInt32(RDR.GetOrdinal("EmployeeID")) Emp.EmployeeName = RDR.GetString(RDR.GetOrdinal("LastName")) & " " & RDR.GetString(RDR.GetOrdinal("FirstName")) Funcionarios.Add(Emp) End While RDR.Close() Return Funcionarios End Function End Class

Classe NWCliente
Repita o procedimento feito para criar a classe NWProduto e crie a classe NWCliente. Nesta classe, vamos definir duas variveis, sobrescrever a funo ToString e definir o mtodo GetTodosClientes que retorna uma lista de Clientes:
Public Class NWCliente Public CustomerID As String Public CustomerName As String Public Overrides Function ToString() As String Return CustomerName End Function Public Shared Function GetTodosClientes() As List(Of NWCliente) Dim CMD As New SqlClient.SqlCommand Dim Clientes As New List(Of NWCliente) CMD.CommandText = "SELECT * FROM Customers" CMD.CommandType = CommandType.Text Dim CN As New SqlClient.SqlConnection(strConexao) CMD.Connection = CN CN.Open() Dim RDR As SqlClient.SqlDataReader RDR = CMD.ExecuteReader() While RDR.Read Dim Cust As New NWCliente Cust.CustomerID = RDR.GetString(RDR.GetOrdinal("CustomerID"))

Cust.CustomerName = RDR.GetString(RDR.GetOrdinal("CompanyName")) Clientes.Add(Cust) End While RDR.Close() Return Clientes End Function End Class

Classe NWPedido
Repita o procedimento feito para criar a classe NWProduto e crie a classe NWPedido. Note que no interior da classe NWpedido temos a definio da classe NWPedidoDetalhes que representa os detalhes de um pedido. O mtodo SalvarPedido() recebe um novo pedido e realiza uma transao para salvar o pedido na tabela Orders e os seus detalhes tabela Order Details:
Public Class NWPedido Public Class NWPedidoDetalhes Public ProductID As Integer Public ProductPrice As Decimal Public ProductQuantity As Integer Public ProductDiscount As Decimal End Class Public Public Public Public OrderDate As Date EmployeeID As Integer CustomerID As String Detalhes As New List(Of NWPedidoDetalhes)

Public Shared Function SalvarPedido(ByVal novoPedido As NWPedido) As Integer Dim CN As New SqlClient.SqlConnection(strConexao) Dim CMD As New SqlClient.SqlCommand CN.Open() CMD.Connection = CN Dim TR As SqlClient.SqlTransaction = CN.BeginTransaction CMD.Transaction = TR CMD.CommandText = "INSERT Orders (OrderDate, EmployeeID, CustomerID) VALUES (@orderDate, @employeeID, @customerID);SELECT Scope_Identity()" CMD.Parameters.AddWithValue("@orderDate", Today) CMD.Parameters.AddWithValue("@employeeID", novoPedido.EmployeeID) CMD.Parameters.AddWithValue("@customerID", novoPedido.CustomerID) Dim OrderID As Int32 Try OrderID = System.Convert.ToInt32(CMD.ExecuteScalar) Catch ex As Exception TR.Rollback() CN.Close() Throw ex End Try For Each det As NWPedidoDetalhes In novoPedido.Detalhes CMD.CommandText = "INSERT [Order Details] (OrderID, ProductID, UnitPrice, Quantity) VALUES(@OrderID, @productID, @price, @quantity)" CMD.Parameters.Clear() CMD.Parameters.AddWithValue("@orderID", OrderID) CMD.Parameters.AddWithValue("@productID", det.ProductID) CMD.Parameters.AddWithValue("@price", det.ProductPrice) CMD.Parameters.AddWithValue("@quantity", det.ProductQuantity) Try CMD.ExecuteNonQuery() Catch ex As Exception TR.Rollback() CN.Close() Throw ex End Try Next TR.Commit() CN.Close() Return OrderID

End Function End Class

Definindo o cdigo do projeto


Vamos incluir um mdulo no projeto. No menu Project, selecione Add New Item e selecione o template Module informando o nome Conexao.vb. A seguir, defina nele a nossa string de conexo para que a mesma seja visvel em todo o projeto conforme abaixo:
Module Conexao Public strConexao As String = "Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True" End Module

A nossa string de conexo aponta para o banco de dados Northwind.mdf do SQL Server no servidor local SQLExpress. Agora que temos as classes com os mtodos definidos e a string de conexo podemos partir para criar as funcionalidades que iro fazer a aplicao funcionar. No incio do formulrio frmSQL vamos definir um objeto Connection usando a string de conexo definida para se conectar com o banco dados: Dim CN As New SqlClient.SqlConnection(strConexao) No evento Load do formulrio, vamos incluir o cdigo para carregar os dois controles ComboBox:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load cboFuncionarios.DisplayMember = "EmployeeName" cboFuncionarios.ValueMember = "EmployeeID" For Each func As NWFuncionario In NWFuncionario.GetTodosFuncionarios cboFuncionarios.Items.Add(func) Next cboClentes.DisplayMember = "CompanyName" cboClentes.ValueMember = "CustomerID" For Each cli As NWCliente In NWCliente.GetTodosClientes cboClentes.Items.Add(cli) Next End Sub

Vamos criar agora as seguintes rotinas: 1. AdicionarProdutos() inclui as informaes do controle TextBox no controle ListView e chama a rotina AtualizaTotal(); 2. AtualizaTotal() Percorre o ListView e totaliza os produtos; 3. LimpaTextBox() Limpa as caixas de texto; O cdigo das rotinas exibido abaixo:
Private Sub AdicionarProduto() Dim LI As New ListViewItem LI.Text = txtID.Text LI.SubItems.Add(txtProduto.Text) LI.SubItems.Add(txtPreco.Text) LI.SubItems.Add(txtQtde.Text) LI.SubItems.Add(txtSubtotal.Text) ListView1.Items.Add(LI) AtualizaTotal() End Sub

Private Sub AtualizaTotal() Dim items As Integer Dim total As Decimal For Each LI As ListViewItem In ListView1.Items items += Integer.Parse(LI.SubItems(3).Text) total += Decimal.Parse(LI.SubItems(4).Text) Next txtItems.Text = items.ToString txtTotal.Text = total.ToString("#,###.00") End Sub Private Sub LimpaTextBox() txtID.Text = "" txtProduto.Text = "" txtPreco.Text = "" txtQtde.Text = "" txtSubtotal.Text = "" End Sub

Agora, vamos tratar os seguintes eventos do controle ListView1: 1. ColumnWidthChanged Rearranja a largura da coluna do controle ListView1; 2. KeyUp Verifica se foi pressionada a tecla Del ou ESC e conforme o caso, atualiza os totais ou limpa as caixas de textos; 3. SelectedIndexChanged Chama a rotina ExibeDetalhe() O cdigo do tratamento para esses eventos exibido a seguir:
Private Sub ListView1_ColumnWidthChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.ColumnWidthChangedEventArgs) Handles ListView1.ColumnWidthChanged txtItems.Left = ListView1.Left + ListView1.Columns(0).Width + ListView1.Columns(1).Width + ListView1.Columns(2).Width txtItems.Width = ListView1.Columns(3).Width txtTotal.Left = txtItems.Left + txtItems.Width txtTotal.Width = ListView1.Columns(4).Width End Sub Private Sub ListView1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles ListView1.KeyUp If e.KeyCode = Keys.Delete And ListView1.SelectedItems.Count > 0 Then ListView1.SelectedItems(0).Remove() AtualizaTotal() End If If e.KeyCode = Keys.Escape Then LimpaTextBox() txtID.Focus() End If End Sub Private Sub ListView1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListView1.SelectedIndexChanged ExibeDetalhe() End Sub

A rotina ExibeDetalhe() obtm os dados do controle ListView e exibe-os nos controle TextBox:
Private Sub ExibeDetalhe() If ListView1.SelectedItems.Count > 0 Then txtID.Text = ListView1.SelectedItems(0).Text txtProduto.Text = ListView1.SelectedItems(0).SubItems(1).Text txtPreco.Text = ListView1.SelectedItems(0).SubItems(2).Text txtQtde.Text = ListView1.SelectedItems(0).SubItems(3).Text txtSubtotal.Text = ListView1.SelectedItems(0).SubItems(4).Text End If End Sub

Vamos tratar o evento KeyUp do controle TxtID para que, aps o usurio digitar um cdigo de produto ao pressionar a tecla ENTER, seja feita uma busca na tabela Products e seja obtido os dados do produto que sero exibidos no formulrio:
Private Sub txtID_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtID.KeyUp If e.KeyCode = Keys.Enter Then If txtID.Text.Length > 0 Then Dim P As NWProduto Dim todosProdutos As List(Of NWProduto) = NWProduto.getProdutoPorId(txtID.Text.Trim) If todosProdutos.Count = 1 Then txtProduto.Text = todosProdutos(0).ProductName txtPreco.Text = todosProdutos(0).ProductPrice.ToString("#.00") txtQtde.Focus() Else ListView2.Items.Clear() For Each P In todosProdutos Dim LI As New ListViewItem LI.Text = P.ProductID LI.SubItems.Add(P.ProductName) LI.SubItems.Add(P.ProductPrice.ToString("#,###.00")) ListView2.Items.Add(LI) Next If ListView2.Items.Count > 0 Then ListView2.Visible = True ListView2.Items(0).Selected = True ListView2.Capture = True ListView2.Focus() Else txtID.Clear() txtID.Focus() End If End If End If End If If e.KeyData = Keys.Down Then If ListView1.Items.Count > 0 Then LimpaTextBox() ListView1.Items(0).Selected = True ListView1.Focus() End If End If End Sub

Agora, vamos tratar o evento KeyUp do TextBox txtQtde de forma que, aps informar a quantidade e pressionada a tecla ENTER, seja calculado o total e as informaes sejam exibidas no controle ListView configurando assim um novo pedido:
Private Sub txtQty_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtQtde.KeyUp If txtProduto.Text.Trim = "" Then MsgBox("Informe o cdigo ou nome do produto!") Exit Sub End If If e.KeyData = Keys.Enter Then Dim qtde As Integer Integer.TryParse(txtQtde.Text, qtde) If qty > 0 Then txtSubtotal.Text = (Decimal.Parse(txtPreco.Text) * qtde).ToString("#,###.00") AdicionarProduto() LimpaTextBox() txtID.Focus() Else txtQtde.Text = "" End If End If If e.KeyData = Keys.Escape Then LimpaTextBox() txtID.Focus() End If

End Sub

No evento Click do boto Salvar Pedido temos o cdigo que salva o pedido e seus detalhes :
Private Sub btnSalvar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSalvar.Click Dim novoPedido As New NWPedido novoPedido.OrderDate = Today novoPedido.CustomerID = CType(cboClentes.SelectedItem, NWCliente).CustomerID novoPedido.EmployeeID = CType(cboFuncionarios.SelectedItem, NWFuncionario).EmployeeID For Each LI As ListViewItem In ListView1.Items Dim novoDetalhe As New NWPedido.NWPedidoDetalhes novoDetalhe.ProductID = LI.Text novoDetalhe.ProductPrice = System.Convert.ToDecimal(LI.SubItems(2).Text) novoDetalhe.ProductQuantity = System.Convert.ToInt32(LI.SubItems(3).Text) novoPedido.Detalhes.Add(novoDetalhe) Next Dim orderID As Integer Try orderID = NWPedido.SalvarPedido(novoPedido) Catch ex As Exception MsgBox("Falha ao gravar o pedido no banco de dados " & vbCrLf & ex.Message) Exit Sub End Try MsgBox("Pedido " & orderID & " gravado com sucesso !") End Sub

No evento Click do boto Novo Pedido apenas limpamos as caixas de texto e colocamos o foco no controle txtID:
Private Sub btnNovo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNovo.Click LimpaTextBox() txtID.Focus() End Sub

Para concluir vamos tratar os eventos KeyUp e LostFocus do controle ListView2:


Private Sub ListView2_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles ListView2.KeyUp If ListView2.Visible And ListView2.SelectedItems.Count = 1 Then If e.KeyCode = Keys.Enter Then txtID.Text = ListView2.SelectedItems(0).Text txtProduto.Text = ListView2.SelectedItems(0).SubItems(1).Text txtPreco.Text = System.Convert.ToDecimal(ListView2.SelectedItems(0).SubItems(2).Text).ToString("#,###.00") ListView2.Visible = False txtQtde.Focus() End If End If End Sub Private Sub ListView2_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListView2.LostFocus ListView2.Visible = False If ListView2.Visible = True Then txtID.Focus() End If End Sub

Agora s alegria! Vamos executar o projeto e incluir um novo pedido. Aps informar os dados e clicar no boto Salvar Pedido, teremos o seguinte resultado:

Dessa forma, neste projeto tivemos que definir as nossas classes de negcio para poder implementar a funcionalidade desejada. Na segunda parte do artigo iremos implementar a mesma funcionalidade usando o LINQ to SQL e comparar qual das duas mais eficiente.

.NET + Desenvolvimento

VB .NET Atualizando tabelas relacionadas com LINQ Parte 02


quarta-feira, 10/10/2012 s 09h10, por Jos Carlos Macoratti Na primeira parte deste artigo, mostrei como podemos atualizar dados de tabelas relacionadas usando ADO .NET. Usando o mesmo cenrio vou mostrar, a ttulo de comparao, como fazer a mesma tarefa usando LINQ to SQL. Vamos ao nosso cenrio Vamos partir de um modelo de dados simples e que j esta pronto para uso, e por isso vamos usar o banco de dados Northwind.mdf. Este banco de dados possui diversas tabelas relacionadas, mas nosso interesse est focado nas tabelas: Orders, Orders Details, Suppliers, Products, Customers e Employees.

Abaixo vemos o relacionamento existente entre essas tabelas:

Nosso objetivo ser atualizar as tabelas Orders e Orders Details com informaes obtidas de um formulrio que simular o envio de um pedido e seus detalhes. Embora as demais tabelas no sejam atualizadas, iremos precisar de suas informaes.

Como temos o modelo de dados j pronto, eu vou iniciar mostrando como ser o formulrio de entrada de dados usado na aplicao. Os recursos necessrios para acompanhar este artigo so:

Visual Basic 2010 Express Edition; SQL Server 2008 Express; Banco de dados Northwind.mdf.

Criando o mapeamento das tabelas usando LINQ to SQL


Abra o Visual Basic 2010 Express Edition e crie um novo projeto do tipo Windows Forms Application com o nome NW_Pedidos_LINQ. Altere o nome do formulrio padro para frmLINQ.vb e inclua os seguintes controles a partir da ToolBox no formulrio:

2 Combobox cboClientes e cboFuncionarios; 5 TextBox txtID, txtProduto (ReadOnly=True), txtPreco (ReadOnly=True), txtQtde, txtSubtotal (ReadOnly=True); 2 TextBox txtItems e txtTotal; 4 TextBox txtNome, txtEndereco, txtCidade e txtRegiao; 2 Buttons btnSalvar e btnNovo.

Os dois controles Combobox devero ser preenchidos quando o formulrio for carregado, permitindo que o usurio selecione o cliente e o funcionrio. A seguir, o usurio dever informar o cdigo do produto e ao teclar ENTER ser realizada uma busca e o nome do produto e seu preo unitrio sero exibidos, bastando ao usurio informar a quantidade desejada para que o valor total seja calculado e o novo pedido exibido no controle ListView.

A seguir, o usurio deve informar os dados do destinatrio: Nome, Endereo, Cidade e Regio e clicar no boto Salvar Pedido para persistir os dados do novo pedido e seus detalhes.

Este cenrio muito frequente em aplicaes comerciais. Vamos, ento, mostrar como implementar o cdigo das funcionalidades envolvidas nesta operao.

Definindo o mapeamento com LINQ to SQL


Diferentemente da verso ADO .NET (primeira parte do artigo), eu no vou criar as classes do nosso domnio via cdigo, mas vou realizar o mapeamento objeto relacional usando o LINQ to SQL, que uma implementao do LINQ para o SQL Server. Dessa forma, as classes sero geradas automaticamente a partir das tabelas do banco de dados.

O que LINQ ?

LINQ Language integrated Query um conjunto de recursos introduzidos no .NET Framework 3.5 que permitem a realizao de consultas diretamente em base de dados , documentos XML , estrutura de dados, coleo de objetos, etc. usando uma sintaxe parecida com a linguagem SQL.

O que LINQ to SQL ?

LINQ to SQL uma implementao especfica to LINQ para o SQL Server que converte consultas escritas em C# ou Visual Basic em SQL dinmico, provendo uma interface que permite mapear os objetos do banco de dados gerando as classes para realizar as operaes usando a sintaxe LINQ; tambm permite realizar alteraes nos objetos e atualizar o banco de dados. Ento, atravs do mapeamento com o LINQ to SQL, nossas classes sero geradas automaticamente e teremos acesso a elas atravs de um contexto gerado em nossa aplicao. Vamos incluir em nosso projeto o recurso LINQ to SQL. Acione o menu Project e clique em Add New Item. Na janela Templates, selecione o item LINQ to SQL Classes alterando o seu nome para Northwind.dbml e clicando no boto Add:

Neste momento ser exibida a janela do descritor Objeto Relacional. Expanda os objetos do banco de dados Northwind.mdf e selecione as tabelas Customers, Employees, Order Details, Orders, Prodcuts arrastando-as e soltandoas na janela Object Relational Designer:

As tabelas do banco de dados sero mapeadas como classes (campos como propriedades, procedures e funes como mtodos) e voc ter no Descritor o conjunto de classes que representam o banco de dados; O arquivo Northwind.dbml contm o arquivo XML com informaes sobre o leiaute das tabelas que foram mapeadas e tambm o descritor contendo as classes geradas pelo mapeamento. Aps encerrar o mapeamento, voc j ter acesso

aos recursos do LINQ To SQL com direito a intellisense completo das informaes referente as tabelas mesmo sem conhecer nada sobre elas. O acesso ser feito atravs da criao de uma instncia da classe DataContext identificada no nosso exemplo como NorthwindDataContext:

Nossa prxima tarefa ser criar uma classe para tratar o contexto e criar os mtodos para acessarem as informaes das classes que foram mapeadas pelo LINQ to SQL.

Definindo o cdigo do projeto


Vamos incluir uma classe em nosso projeto que ir instanciar o nosso Contexto e definir nesta classe alguns mtodos para acessar as informaes das classes mapeadas a partir das tabelas do Northwind.mdf. No menu Project, clique em Add Class e, a seguir, selecione o template Class e informe o nome NWContexto.vb e clique no boto Add:

Vamos incluir uma referncia ao namespace System.Transactions em nosso projeto. No menu Project clique em Add Reference e em seguida clique na guia .NET e selecione o componente System.Transactions e clique em OK:

O namespace System.Transactions contm classes que lhe permitem escrever a sua prpria aplicao transacional e gerenciar os recursos. Voc pode criar e participar em uma transao Local ou distribuda com um mais participantes. Agora vamos definir os seguintes mtodos na classe NWContexto:

GetProdutoPorID() retorna um produto pelo seu cdigo; GetFuncionarios() retorna uma lista de funcionrios; GetClientes() retorna uma lista de clientes; SalvarPedido() salva o pedido no banco de dados.

O cdigo destes mtodos esta definido a seguir:


Public Class NWContexto Public Function GetProdutoPorID(ByVal productID As Integer) As Product Dim ctx As New NorthwindDataContext Dim prod = (From p In ctx.Products Where p.ProductID = productID Select p).FirstOrDefault Return prod End Function Public Function GetFuncionarios() As List(Of Employee) Dim ctx As New NorthwindDataContext Dim funcis = (From emp In ctx.Employees Select emp).ToList Return funcis End Function Public Function GetClientes() As List(Of Customer) Dim ctx As New NorthwindDataContext Dim clientes = (From cust In ctx.Customers Select cust).ToList Return clientes End Function Public Shared Function SalvarPedido(ByVal novoPedido As Order) As Integer Dim ctx As New NorthwindDataContext Using TR As New System.Transactions.TransactionScope ctx.Orders.InsertOnSubmit(novoPedido) Try ctx.SubmitChanges() TR.Complete() Catch ex As Exception Return (-1) End Try End Using Return novoPedido.OrderID End Function End Class

Observe que em todos os mtodos criamos uma instncia da classe DataContext identificada no nosso exemplo por NorthwindDataContext; Dim ctx As New NorthwindDataContext Aqui o banco de dados mapeado em um DataContext permitindo acesso a tabelas de forma transparente sem nos preocuparmos com conexo. O DataContext utiliza a interface IDbConnection do ADO.NET para acessar o armazenamento e pode ser inicializado tanto com um objeto de conexo ADO.NET estabelecido, ou com uma string de conexo que possa ser utilizada para criar a conexo. O DataContext o mecanismo usado para que seja feita a seleo no banco de dados, ficando responsvel por traduzir as selees e alteraes executando-as no banco de dados e transformando o resultado em objetos. A seguir, usamos consultas usando a sintaxe LINQ conforme abaixo:

Dim prod = (From p In ctx.Products Where p.ProductID = productID Select p).FirstOrDefault A consulta LINQ To SQL inicia com a clusula From e em seguida o operador de condio Where, depois ordenao com Order By e, no final, o operador de seleo Select. A clusula From a mais importante do LINQ To SQL, pois usada em todas as consultas. Uma consulta deve sempre comear com From (o Select pode estar implcito o From no). No exemplo, o mtodo SingeOrDefault retorna um nico e especfico elemento da sequncia de valores ou um valor padro se o elemento no for encontrado. No mtodo SalvarPedido, estamos incluindo um pedido na tabela Orders usando o mtodo InsertOnSubmit(). No mtodo SalvarPedido, aps definirmos valores para um novo pedido, estamos usando dois mtodos LINQ:

InsertOnSubmit() Este mtodo adiciona uma entidade , no caso a entidade novoPedido que do tipo Orders, em um estado pendente de incluso a tabela Orders; SubmitChanges() Este mtodo efetiva a incluso atual feita pelo InsertOnSubmit() na tabela do banco de dados. Deve ser chamado aps o mtodo InsertOnSubmit().

Quando SubmitChanges() invocado, o LINQ To SQL automaticamente gera e executa comandos SQL a fim de transmitir as alteraes de volta ao banco de dados. Voc pode, no entanto, sobrescrever este comportamento chamando uma stored procedure. Vejamos agora o tratamento dos eventos do controles do formulrio e as rotinas auxiliares. No evento Load do formulrio:
Private Sub FrmLINQ_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim NWDados As New NWContexto cboFuncionarios.DisplayMember = "FirstName" cboFuncionarios.ValueMember = "EmployeeID" For Each func In NWDados.GetFuncionarios cboFuncionarios.Items.Add(func) Next cboClientes.ValueMember = "CustomerID" cboClientes.DisplayMember = "CompanyName" For Each cli In NWDados.GetClientes cboClientes.Items.Add(cli) Next End Sub

No cdigo criamos uma instncia da classe NWContexto e usamos os mtodos GetFuncionarios e GetClientes. As rotinas AdicionarProduto(), AtualizaTotal() e LimpaTextBox() no sofreram alterao:
Private Sub AdicionarProduto() Dim LI As New ListViewItem LI.Text = txtID.Text LI.SubItems.Add(txtProduto.Text) LI.SubItems.Add(txtPreco.Text) LI.SubItems.Add(txtQtde.Text) LI.SubItems.Add(txtSubtotal.Text) ListView1.Items.Add(LI) AtualizaTotal() End Sub Private Dim Dim For Sub AtualizaTotal() items As Integer total As Decimal Each LI As ListViewItem In ListView1.Items

items += Integer.Parse(LI.SubItems(3).Text) total += Decimal.Parse(LI.SubItems(4).Text) Next txtItems.Text = items.ToString txtTotal.Text = total.ToString("#,###.00") End Sub Private Sub LimpaTextBox() txtID.Text = "" txtProduto.Text = "" txtPreco.Text = "" txtQtde.Text = "" txtSubtotal.Text = "" End Sub

Os eventos ColumnWidthChanged, KeyUp e SelectedIndexChanged do controle ListView tambm no sofreram alterao alguma:
Private Sub ListView1_ColumnWidthChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.ColumnWidthChangedEventArgs) Handles ListView1.ColumnWidthChanged txtItems.Left = ListView1.Left + ListView1.Columns(0).Width + ListView1.Columns(1).Width + ListView1.Columns(2).Width txtItems.Width = ListView1.Columns(3).Width txtTotal.Left = txtItems.Left + txtItems.Width txtTotal.Width = ListView1.Columns(4).Width End Sub Private Sub ListView1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles ListView1.KeyUp If e.KeyCode = Keys.Delete And ListView1.SelectedItems.Count > 0 Then ListView1.SelectedItems(0).Remove() AtualizaTotal() End If If e.KeyCode = Keys.Escape Then LimpaTextBox() txtID.Focus() End If End Sub Private Sub ListView1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListView1.SelectedIndexChanged ExibeDetalhe() End Sub

A rotina ExibeDetalhe() tambm no sofreu mudana:


Private Sub ExibeDetalhe() If ListView1.SelectedItems.Count > 0 Then txtID.Text = ListView1.SelectedItems(0).Text txtProduto.Text = ListView1.SelectedItems(0).SubItems(1).Text txtPreco.Text = ListView1.SelectedItems(0).SubItems(2).Text txtQtde.Text = ListView1.SelectedItems(0).SubItems(3).Text txtSubtotal.Text = ListView1.SelectedItems(0).SubItems(4).Text End If End Sub

No evento KeyUp do controle TxtID onde logo aps o usurio digitar um cdigo de produto ao pressionar a tecla ENTER feita uma busca na tabela Products e so obtidos os dados do produto para exibio no formulrio. O cdigo deste evento foi alterado conforme abaixo:
Private Sub txtID_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtID.KeyUp If e.KeyCode = Keys.Enter Then If txtID.Text.Length > 0 Then Dim P As Product = (New NWContexto).GetProdutoPorID(txtID.Text.Trim) If P IsNot Nothing Then

Else

txtProduto.Text = P.ProductName txtPreco.Text = P.UnitPrice.ToString txtQtde.Focus()

txtID.Clear() End If End If End If If e.KeyData = Keys.Down Then If ListView1.Items.Count > 0 Then LimpaTextBox() ListView1.Items(0).Selected = True ListView1.Focus() End If End If End Sub

Neste cdigo estamos usando o mtodo GetProdutoPorID() para obter o produto pelo cdigo informado usando uma instncia da classe DataContext. Agora vamos tratar o evento KeyUp do TextBox txtQtde de forma que aps informar a quantidade e pressionada a tecla ENTER, seja calculado o total e as informaes sejam exibidas no controle ListView configurando assim um novo pedido:
Private Sub txtQtde_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtQtde.KeyUp If e.KeyData = Keys.Enter Then Dim qty As Integer Integer.TryParse(txtQtde.Text, qty) If qty > 0 Then txtSubtotal.Text = (Decimal.Parse(txtPreco.Text) * qty).ToString("#,###.00") AdicionarProduto() LimpaTextBox() txtID.Focus() Else txtQtde.Text = "" End If End If If e.KeyData = Keys.Escape Then LimpaTextBox() txtID.Focus() End If End Sub

No evento Click do boto Salvar Pedido temos o cdigo que salvar o pedido e seus detalhes :
Private Sub btnSalvar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSalvar.Click If ListView1.Items.Count = 0 Then MsgBox("Inclua um ou mais itens para o pedido.") Exit Sub End If If cboClientes.SelectedIndex = -1 Then MsgBox("Selecione um cliente") Exit Sub End If If cboFuncionarios.SelectedIndex = -1 Then MsgBox("Selecione um funcionrio") Exit Sub End If Dim novoPedido As New Order novoPedido.CustomerID = CType(cboClientes.SelectedItem, Customer).CustomerID novoPedido.EmployeeID = CType(cboFuncionarios.SelectedItem, Employee).EmployeeID novoPedido.OrderDate = Today For Each LI As ListViewItem In ListView1.Items Dim novoDetalhe As New Order_Detail

Next

novoDetalhe.ProductID = LI.Text novoDetalhe.UnitPrice = Decimal.Parse(LI.SubItems(2).Text) novoDetalhe.Quantity = Integer.Parse(LI.SubItems(3).Text) novoDetalhe.Discount = 0D novoPedido.Order_Details.Add(novoDetalhe)

Dim ID As Integer ID = NWContexto.SalvarPedido(novoPedido) If ID > 0 Then MsgBox("Order " & novoPedido.OrderID.ToString & " submetido com sucesso...") Else MsgBox("Falha ao inserir um novo pedido no banco de dados") End If End Sub

No evento Click do boto Novo Pedido apenas limpamos as caixas de texto e colocamos o foco no controle txtID:
Private Sub btnNovo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNovo.Click LimpaTextBox() txtID.Focus() End Sub

Agora s alegria! Mas antes de prosseguir, vamos comparar o que mudou com a utilizao do LINQ to SQL em nosso projeto. Notou que no tivemos que utilizar instrues SQL para acessar e persistir informaes no banco de dados? otou tambm que no tivemos que nos preocupar com a definio de objetos connection, command, adapter, etc? A utilizao do LINQ to SQL abstraiu toda essa parte, permitindo um ganho de produtividade, pois o projeto ficou mais enxuto. Vamos executar o projeto e incluir um novo pedido. Aps informar os dados e clicar no boto Salvar Pedido teremos o seguinte resultado:

Dessa forma, neste projeto tivemos que definir as nossas classes de negcio para poder implementar a funcionalidade desejada e ao invs de fazer isso via cdigo usamos o LINQ to SQL para gerar as classes via mapeamento OR/M.