22
VB .NET – Tradutor Multilíngue baseado no Google Translate (OSSkin.Net) sexta-feira, 20/05/2011 às 10h05, por José Carlos Macoratti Adicione o recurso da tradução ao seus programas VB.NET. Use o tradutor de sites do Google em seus programas e ofereça acesso instantâneo a traduções automáticas. Comece informando o texto a traduzir, depois escolha o idioma de destino para a tradução e… pronto! Seu texto será traduzido usando o Google Translate.

VB .NET

Embed Size (px)

Citation preview

Page 1: VB .NET

VB .NET – Tradutor Multilíngue baseado no Google Translate (OSSkin.Net)sexta-feira, 20/05/2011 às 10h05, por José Carlos Macoratti

Adicione o recurso da tradução ao seus programas VB.NET. Use o tradutor de sites do Google em seus programas e ofereça acesso instantâneo a traduções automáticas.

Comece informando o texto a traduzir, depois escolha o idioma de destino para a tradução e… pronto! Seu texto será traduzido usando o Google Translate.

O projeto Visual Basic usa os controle WebBrowser, ProgressBar, ToolStip, NotifyIcon e ContextMenu. A aplicação também usa o componente OSSkin.Net que permite utilizar Skins em aplicações .NET.

Page 2: VB .NET

O componente OSSkin.Net permite que os desenvolvedores usem o recurso de skins em aplicações 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.

Graças aos recursos avançados concebidos inteiramente em C#, ele é o único produto disponível atualmente que permite mudar completamente a aparência de todas as formas de janelas,formulários, controles e diálogos.

O código da aplicação é trivial, veja abaixo o exemplo da chamada para a conversão Inglês -> Português:

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…

Page 3: VB .NET

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

Este artigo faz uma revisão dos conceitos da tecnologia ADO .NET através de um exemplo prático. 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 informações obtidas de um formulário que simulará o envio de um pedido e seus detalhes. Embora as demais tabelas não sejam atualizadas, iremos precisar de suas informações.

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.

Além de revisarmos os conceitos relacionados com os objetos básicos da ADO .NET, como DataReader, DataAdapter e SqlCommand. Iremos trabalhar com classes, transações e instruções SQL parametrizadas.

Como temos o modelo de dados já pronto, eu vou iniciar mostrando como será o formulário de entrada de dados usado na aplicação. Os recursos necessários para acompanhar este artigo são:

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

Criando o projeto e definindo as classes do domínio

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 formulário padrão para frmSQL.vb e inclua os seguintes controles a partir da ToolBox no formulário:

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

Page 4: VB .NET

Os dois controles Combobox deverão ser preenchidos quando o formulário for carregado, permitindo que o usuário selecione o cliente e o funcionário.

A seguir, o usuário deverá informar o código do produto e, ao teclar ENTER, será realizada uma busca e o nome do produto e seu preço unitário será exibido, bastando ao usuário informar a quantidade desejada para que o valor total seja calculado e o novo pedido exibido no controle ListView.

A seguir, o usuário deve informar os dados do destinatário: Nome, Endereço, Cidade e Região e clicar no botão Salvar Pedido para persistir os dados do novo pedido e seus detalhes. Este cenário é muito frequente em aplicações comerciais.

Vamos, então, mostrar como implementar o código das funcionalidades envolvidas nesta operação.

1. Definindo as classes do domínio

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 código abaixo na classe NWProdutos; nele estamos definindo três variáveis com o mesmo nome dos campos da tabela Products e o método getProdutoPorId() que retorna uma lista de produtos:

Page 5: VB .NET

Public Class NWProduto

Public ProductID As IntegerPublic ProductName As StringPublic 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.SqlCommandDim RDR As SqlClient.SqlDataReader

If IsNumeric(productID) ThenCMD.CommandText = "SELECT * FROM products WHERE ProductID=@ProductID"CMD.CommandType = CommandType.TextCMD.Parameters.AddWithValue("@ProductID", productID)CMD.Connection = CNCN.Open()RDR = CMD.ExecuteReaderDim prod As NWProduto = Nothing

If RDR.Read Thenprod = New NWProdutoprod.ProductID = RDR.GetInt32(RDR.GetOrdinal("ProductID"))prod.ProductName = RDR.GetString(RDR.GetOrdinal("ProductName"))prod.ProductPrice = RDR.GetDecimal(RDR.GetOrdinal("UnitPrice"))produtos.Add(prod)End IfElseCMD.CommandText = "SELECT * FROM Products WHERE ProductName LIKE '%' + @ProductID + '%'"CMD.CommandType = CommandType.TextCMD.Parameters.AddWithValue("@ProductID", productID)CMD.Connection = CNCN.Open()RDR = CMD.ExecuteReader

While RDR.ReadDim prod As New NWProdutoprod.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 IfCN.Close()Return produtosEnd Function

End Class

O método getProdutoPorID retorna uma lista de produtos pelo código informado.

Classe NWFuncionario

Repita o procedimento feito para criar a classe NWProduto e crie a classe NWFuncionario. Nesta classe definimos duas variáveis, o método GetTodosFuncionarios(), que retorna uma lista de funcionários, e sobrescrevemos o método ToString() que agora retorna o nome do funcionário.

Public Class NWFuncionario

Public EmployeeID As IntegerPublic EmployeeName As StringPublic Overrides Function ToString() As StringReturn EmployeeNameEnd Function

Public Shared Function GetTodosFuncionarios() As List(Of NWFuncionario)Dim CMD As New SqlClient.SqlCommandDim Funcionarios As New List(Of NWFuncionario)

Page 6: VB .NET

CMD.CommandText = "SELECT * FROM Employees"CMD.CommandType = CommandType.TextDim CN As New SqlClient.SqlConnection(strConexao)CMD.Connection = CNCN.Open()Dim RDR As SqlClient.SqlDataReaderRDR = CMD.ExecuteReader()While RDR.ReadDim Emp As New NWFuncionarioEmp.EmployeeID = RDR.GetInt32(RDR.GetOrdinal("EmployeeID"))Emp.EmployeeName = RDR.GetString(RDR.GetOrdinal("LastName")) & " " & RDR.GetString(RDR.GetOrdinal("FirstName"))Funcionarios.Add(Emp)End WhileRDR.Close()Return Funcionarios

End FunctionEnd Class

Classe NWCliente

Repita o procedimento feito para criar a classe NWProduto e crie a classe NWCliente. Nesta classe, vamos definir duas variáveis, sobrescrever a função ToString e definir o método GetTodosClientes que retorna uma lista de Clientes:

Public Class NWClientePublic CustomerID As StringPublic CustomerName As StringPublic Overrides Function ToString() As StringReturn CustomerNameEnd Function

Public Shared Function GetTodosClientes() As List(Of NWCliente)Dim CMD As New SqlClient.SqlCommandDim Clientes As New List(Of NWCliente)CMD.CommandText = "SELECT * FROM Customers"CMD.CommandType = CommandType.TextDim CN As New SqlClient.SqlConnection(strConexao)CMD.Connection = CNCN.Open()Dim RDR As SqlClient.SqlDataReaderRDR = CMD.ExecuteReader()While RDR.ReadDim Cust As New NWClienteCust.CustomerID = RDR.GetString(RDR.GetOrdinal("CustomerID"))Cust.CustomerName = RDR.GetString(RDR.GetOrdinal("CompanyName"))Clientes.Add(Cust)End WhileRDR.Close()Return ClientesEnd 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 definição da classe NWPedidoDetalhes que representa os detalhes de um pedido. O método SalvarPedido() recebe um novo pedido e realiza uma transação para salvar o pedido na tabela Orders e os seus detalhes tabela Order Details:

Public Class NWPedido

Public Class NWPedidoDetalhesPublic ProductID As IntegerPublic ProductPrice As DecimalPublic ProductQuantity As IntegerPublic ProductDiscount As DecimalEnd Class

Page 7: VB .NET

Public OrderDate As DatePublic EmployeeID As IntegerPublic CustomerID As StringPublic Detalhes As New List(Of NWPedidoDetalhes)

Public Shared Function SalvarPedido(ByVal novoPedido As NWPedido) As IntegerDim CN As New SqlClient.SqlConnection(strConexao)Dim CMD As New SqlClient.SqlCommandCN.Open()CMD.Connection = CNDim TR As SqlClient.SqlTransaction = CN.BeginTransactionCMD.Transaction = TRCMD.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 Int32TryOrderID = System.Convert.ToInt32(CMD.ExecuteScalar)Catch ex As ExceptionTR.Rollback()CN.Close()Throw exEnd TryFor Each det As NWPedidoDetalhes In novoPedido.DetalhesCMD.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)TryCMD.ExecuteNonQuery()Catch ex As ExceptionTR.Rollback()CN.Close()Throw exEnd TryNextTR.Commit()CN.Close()Return OrderIDEnd Function

End Class

Definindo o código do projeto

Vamos incluir um módulo 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 conexão para que a mesma seja visível em todo o projeto conforme abaixo:

Module ConexaoPublic strConexao As String = "Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True"End Module

A nossa string de conexão aponta para o banco de dados Northwind.mdf do SQL Server no servidor local SQLExpress. Agora que temos as classes com os métodos definidos e a string de conexão podemos partir para criar as funcionalidades que irão fazer a aplicação funcionar.

No início do formulário frmSQL vamos definir um objeto Connection usando a string de conexão definida para se conectar com o banco dados:

Dim CN As New SqlClient.SqlConnection(strConexao)

Page 8: VB .NET

No evento Load do formulário, vamos incluir o código 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 informações 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 código das rotinas é exibido abaixo:

Private Sub AdicionarProduto()Dim LI As New ListViewItemLI.Text = txtID.TextLI.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 IntegerDim total As DecimalFor Each LI As ListViewItem In ListView1.Itemsitems += Integer.Parse(LI.SubItems(3).Text)total += Decimal.Parse(LI.SubItems(4).Text)NexttxtItems.Text = items.ToStringtxtTotal.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 código 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

Page 9: VB .NET

txtItems.Left = ListView1.Left + ListView1.Columns(0).Width + ListView1.Columns(1).Width + ListView1.Columns(2).WidthtxtItems.Width = ListView1.Columns(3).WidthtxtTotal.Left = txtItems.Left + txtItems.WidthtxtTotal.Width = ListView1.Columns(4).WidthEnd Sub

Private Sub ListView1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles ListView1.KeyUpIf e.KeyCode = Keys.Delete And ListView1.SelectedItems.Count > 0 ThenListView1.SelectedItems(0).Remove()AtualizaTotal()End IfIf e.KeyCode = Keys.Escape ThenLimpaTextBox()txtID.Focus()End IfEnd Sub

Private Sub ListView1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListView1.SelectedIndexChangedExibeDetalhe()End Sub

A rotina ExibeDetalhe() obtém os dados do controle ListView e exibe-os nos controle TextBox:

Private Sub ExibeDetalhe()If ListView1.SelectedItems.Count > 0 ThentxtID.Text = ListView1.SelectedItems(0).TexttxtProduto.Text = ListView1.SelectedItems(0).SubItems(1).TexttxtPreco.Text = ListView1.SelectedItems(0).SubItems(2).TexttxtQtde.Text = ListView1.SelectedItems(0).SubItems(3).TexttxtSubtotal.Text = ListView1.SelectedItems(0).SubItems(4).TextEnd IfEnd Sub

Vamos tratar o evento KeyUp do controle TxtID para que, após o usuário digitar um código de produto ao pressionar a tecla ENTER, seja feita uma busca na tabela Products e seja obtido os dados do produto – que serão exibidos no formulário:

Private Sub txtID_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtID.KeyUpIf e.KeyCode = Keys.Enter ThenIf txtID.Text.Length > 0 ThenDim P As NWProdutoDim todosProdutos As List(Of NWProduto) = NWProduto.getProdutoPorId(txtID.Text.Trim)If todosProdutos.Count = 1 ThentxtProduto.Text = todosProdutos(0).ProductNametxtPreco.Text = todosProdutos(0).ProductPrice.ToString("#.00")txtQtde.Focus()ElseListView2.Items.Clear()For Each P In todosProdutosDim LI As New ListViewItemLI.Text = P.ProductIDLI.SubItems.Add(P.ProductName)LI.SubItems.Add(P.ProductPrice.ToString("#,###.00"))ListView2.Items.Add(LI)NextIf ListView2.Items.Count > 0 ThenListView2.Visible = TrueListView2.Items(0).Selected = TrueListView2.Capture = TrueListView2.Focus()ElsetxtID.Clear()txtID.Focus()End IfEnd IfEnd If

Page 10: VB .NET

End IfIf e.KeyData = Keys.Down ThenIf ListView1.Items.Count > 0 ThenLimpaTextBox()ListView1.Items(0).Selected = TrueListView1.Focus()End IfEnd IfEnd Sub

Agora, vamos tratar o evento KeyUp do TextBox txtQtde de forma que, após informar a quantidade e pressionada a tecla ENTER, seja calculado o total e as informações 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.KeyUpIf txtProduto.Text.Trim = "" ThenMsgBox("Informe o código ou nome do produto!")Exit SubEnd IfIf e.KeyData = Keys.Enter ThenDim qtde As IntegerInteger.TryParse(txtQtde.Text, qtde)If qty > 0 ThentxtSubtotal.Text = (Decimal.Parse(txtPreco.Text) * qtde).ToString("#,###.00")AdicionarProduto()LimpaTextBox()txtID.Focus()ElsetxtQtde.Text = ""End IfEnd IfIf e.KeyData = Keys.Escape ThenLimpaTextBox()txtID.Focus()End IfEnd Sub

No evento Click do botão Salvar Pedido temos o código que salva o pedido e seus detalhes :

Private Sub btnSalvar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSalvar.ClickDim novoPedido As New NWPedidonovoPedido.OrderDate = TodaynovoPedido.CustomerID = CType(cboClentes.SelectedItem, NWCliente).CustomerIDnovoPedido.EmployeeID = CType(cboFuncionarios.SelectedItem, NWFuncionario).EmployeeIDFor Each LI As ListViewItem In ListView1.ItemsDim novoDetalhe As New NWPedido.NWPedidoDetalhesnovoDetalhe.ProductID = LI.TextnovoDetalhe.ProductPrice = System.Convert.ToDecimal(LI.SubItems(2).Text)novoDetalhe.ProductQuantity = System.Convert.ToInt32(LI.SubItems(3).Text)novoPedido.Detalhes.Add(novoDetalhe)NextDim orderID As IntegerTryorderID = NWPedido.SalvarPedido(novoPedido)Catch ex As ExceptionMsgBox("Falha ao gravar o pedido no banco de dados " & vbCrLf & ex.Message)Exit SubEnd TryMsgBox("Pedido " & orderID & " gravado com sucesso !")End Sub

No evento Click do botão 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.ClickLimpaTextBox()txtID.Focus()End Sub

Page 11: VB .NET

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.KeyUpIf ListView2.Visible And ListView2.SelectedItems.Count = 1 ThenIf e.KeyCode = Keys.Enter ThentxtID.Text = ListView2.SelectedItems(0).TexttxtProduto.Text = ListView2.SelectedItems(0).SubItems(1).TexttxtPreco.Text = System.Convert.ToDecimal(ListView2.SelectedItems(0).SubItems(2).Text).ToString("#,###.00")ListView2.Visible = FalsetxtQtde.Focus()End IfEnd IfEnd Sub

Private Sub ListView2_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListView2.LostFocusListView2.Visible = FalseIf ListView2.Visible = True ThentxtID.Focus()End IfEnd Sub

Agora é só alegria! Vamos executar o projeto e incluir um novo pedido. Após informar os dados e clicar no botão “Salvar Pedido”, teremos o seguinte resultado:

Dessa forma, neste projeto tivemos que definir as nossas classes de negócio 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 02quarta-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 cenário vou mostrar, a título de comparação, como fazer a mesma tarefa usando LINQ to SQL.

Vamos ao nosso cenário… 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:

Page 12: VB .NET

Nosso objetivo será atualizar as tabelas Orders e Orders Details com informações obtidas de um formulário que simulará o envio de um pedido e seus detalhes. Embora as demais tabelas não sejam atualizadas, iremos precisar de suas informações.

Como temos o modelo de dados já pronto, eu vou iniciar mostrando como será o formulário de entrada de dados usado na aplicação. Os recursos necessários para acompanhar este artigo são:

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 formulário padrão para frmLINQ.vb e inclua os seguintes controles a partir da ToolBox no formulário:

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 deverão ser preenchidos quando o formulário for carregado, permitindo que o usuário selecione o cliente e o funcionário.

A seguir, o usuário deverá informar o código do produto e ao teclar ENTER será realizada uma busca e o nome do produto e seu preço unitário serão exibidos, bastando ao usuário informar a quantidade desejada para que o valor total seja calculado e o novo pedido exibido no controle ListView.

Page 13: VB .NET

A seguir, o usuário deve informar os dados do destinatário: Nome, Endereço, Cidade e Região e clicar no botão Salvar Pedido para persistir os dados do novo pedido e seus detalhes.

Este cenário é muito frequente em aplicações comerciais. Vamos, então, mostrar como implementar o código das funcionalidades envolvidas nesta operação.

Definindo o mapeamento com LINQ to SQL

Diferentemente da versão ADO .NET (primeira parte do artigo), eu não vou criar as classes do nosso domínio via código, mas vou realizar o mapeamento objeto relacional usando o LINQ to SQL, que é uma implementação do LINQ para o SQL Server. Dessa forma, as classes serão 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 realização de consultas diretamente em base de dados , documentos XML , estrutura de dados, coleção de objetos, etc. usando uma sintaxe parecida com a linguagem SQL.

O que LINQ to SQL ?

LINQ to SQL é uma implementação específica to LINQ para o SQL Server que converte consultas escritas em C# ou Visual Basic em SQL dinâmico, provendo uma interface que permite mapear os objetos do banco de dados gerando as classes para realizar as operações usando a sintaxe LINQ; também permite realizar alterações nos objetos e atualizar o banco de dados.

Então, através do mapeamento com o LINQ to SQL, nossas classes serão geradas automaticamente e teremos acesso a elas através de um contexto gerado em nossa aplicação.

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 botão 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 soltando-as na janela Object Relational Designer:

Page 14: VB .NET

As tabelas do banco de dados serão mapeadas como classes (campos como propriedades, procedures e funções como métodos)  e você terá no Descritor o conjunto de classes que representam o banco de dados;

O arquivo Northwind.dbml contém o arquivo XML com informações sobre o leiaute das tabelas que foram mapeadas e também o descritor contendo as classes geradas pelo mapeamento. Após encerrar o mapeamento, você já terá acesso aos recursos do LINQ To SQL com direito a intellisense completo das informações referente as tabelas mesmo sem conhecer nada sobre elas.

O acesso será feito através da criação de uma instância da classe DataContext identificada no nosso exemplo como NorthwindDataContext:

Nossa próxima tarefa será criar uma classe para tratar o contexto e criar os métodos para acessarem as informações das classes que foram mapeadas pelo LINQ to SQL.

Definindo o código do projeto

Vamos incluir uma classe em nosso projeto que irá instanciar o nosso Contexto e definir nesta classe alguns métodos para acessar as informações 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 botão Add:

Vamos incluir uma referência 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:

Page 15: VB .NET

O namespace System.Transactions contém classes que lhe permitem escrever a sua própria aplicação transacional e gerenciar os recursos. Você pode criar e participar em uma transação Local ou distribuída com um mais participantes.

Agora vamos definir os seguintes métodos na classe NWContexto:

GetProdutoPorID() – retorna um produto pelo seu código; GetFuncionarios() – retorna uma lista de funcionários; GetClientes() – retorna uma lista de clientes; SalvarPedido() – salva o pedido no banco de dados.

O código destes métodos 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

Page 16: VB .NET

Observe que em todos os métodos criamos uma instância 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 conexão. O DataContext utiliza a interface IDbConnection do ADO.NET para acessar o armazenamento e pode ser inicializado tanto com um objeto de conexão ADO.NET estabelecido, ou com uma string de conexão que possa ser utilizada para criar a conexão.

O DataContext é o mecanismo usado para que seja feita a seleção no banco de dados, ficando responsável por traduzir as seleções e alterações 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.ProductsWhere p.ProductID = productIDSelect p).FirstOrDefault

A consulta LINQ To SQL inicia com a cláusula From e em seguida o operador de condição Where, depois ordenação com Order By e, no final, o operador de seleção Select.

A cláusula From é a mais importante do LINQ To SQL, pois é usada em todas as consultas. Uma consulta deve sempre começar com From (o Select pode estar implícito o From não). No exemplo, o método SingeOrDefault retorna um único e específico elemento da sequênciade valores ou um valor padrão – se o elemento não for encontrado.

No método SalvarPedido, estamos incluindo um pedido na tabela Orders usando o método InsertOnSubmit(). No método SalvarPedido, após definirmos valores para um novo pedido, estamos usando dois métodos LINQ:

InsertOnSubmit() – Este método adiciona uma entidade , no caso a entidade novoPedido que é do tipo Orders, em um estado pendente de inclusão a tabela Orders;

SubmitChanges() – Este método efetiva a inclusão atual feita pelo InsertOnSubmit() na tabela do banco de dados. Deve ser chamado após o método InsertOnSubmit().

Quando SubmitChanges() é invocado, o LINQ To SQL automaticamente gera e executa comandos SQL a fim de transmitir as alterações 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 formulário e as rotinas auxiliares.

No evento Load do formulário:

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 código criamos uma instância da classe NWContexto e usamos os métodos GetFuncionarios e GetClientes. As rotinas AdicionarProduto(), AtualizaTotal() e LimpaTextBox() não sofreram alteração:

Private Sub AdicionarProduto() Dim LI As New ListViewItem LI.Text = txtID.Text LI.SubItems.Add(txtProduto.Text) LI.SubItems.Add(txtPreco.Text)

Page 17: VB .NET

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

Os eventos ColumnWidthChanged, KeyUp e SelectedIndexChanged do controle ListView também não sofreram alteração 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() também não sofreu mudança:

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 após o usuário digitar um código de produto ao pressionar a tecla ENTER é feita uma busca na tabela Products e são obtidos os dados do produto para exibição no formulário.

O código deste evento foi alterado conforme abaixo:

Page 18: VB .NET

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 txtProduto.Text = P.ProductName txtPreco.Text = P.UnitPrice.ToString txtQtde.Focus() Else 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 código estamos usando o método GetProdutoPorID() para obter o produto pelo código informado usando uma instância da classe DataContext.

Agora vamos tratar o evento KeyUp do TextBox txtQtde de forma que após informar a quantidade e pressionada a tecla ENTER, seja calculado o total e as informações 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 botão Salvar Pedido temos o código 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 funcionário") Exit Sub End If

Dim novoPedido As New Order novoPedido.CustomerID = CType(cboClientes.SelectedItem, Customer).CustomerID

Page 19: VB .NET

novoPedido.EmployeeID = CType(cboFuncionarios.SelectedItem, Employee).EmployeeID novoPedido.OrderDate = Today For Each LI As ListViewItem In ListView1.Items Dim novoDetalhe As New Order_Detail 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) Next

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 botão 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 utilização do LINQ to SQL em nosso projeto. Notou que não tivemos que utilizar instruções SQL para acessar e persistir informações no banco de dados? otou também que não tivemos que nos preocupar com a definição de objetos connection, command, adapter, etc? A utilização 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. Após informar os dados e clicar no botão – Salvar Pedido – teremos o seguinte resultado:

Dessa forma, neste projeto tivemos que definir as nossas classes de negócio para poder implementar a funcionalidade desejada e ao invés de fazer isso via código usamos o LINQ to SQL para gerar as classes via mapeamento OR/M.