VB .NET - Curso Prático ADO .NET - Desenvolvendo uma aplicação : Definindo o código da Interface - XI


O formulário de pedidos - frmPedidos - permite aos clientes visualizar os filmes selecionados com seu total e os dados do seu cartão de crédito previamente cadastrados. O cliente pode então finalizar o pedido clicando no botão - Finalizar Pedido - ou clicar no botão Cancelar para cancelar o pedido.

Este formulário utiliza as seguintes declarações imports que permite o acesso as classes ADO .NET e ao provedor para o SQL Server:

Imports System.Data
Imports System.Data.SqlClient

No início da classe do formulário temos que declarar as seguintes variáveis:

Private Shared intTotalFilmesSelecionados As Integer
Private Shared pedidoFilmesSelecionados As List(Of Filme)
Private Shared strIDFilmesSelecionadosTemp As String

Essas variáveis são estáticas e serão visíveis em todo o formulário.

Nota:  Uma variável estática na linguagem VB .NET é declarada com a palavra chave Shared e tem sua vida útil até quando o aplicativo estiver em uso. A vida útil é o tempo que ela mantém o seu valor na memória.

Para exibir os pedidos selecionados no formulário de pesquisas - frmPesquisas, o formulário de pedidos deve receber quantidade total dos filmes e a lista de filmes selecionados. Isso é feito através da rotina setFilmesSelecionados() cujo código vemos abaixo:

Public Sub setFilmesSelecionados(ByVal filmesSelecionados As List(Of Filme), ByVal intTotalSelecionados As Integer)
        intTotalFilmesSelecionados = intTotalSelecionados
        pedidoFilmesSelecionados = filmesSelecionados
    End Sub

A obtenção e a exibição das informações no formulário é feita no evento Load que ocorre quando o formulário é carregado pela primeira vez. A seguir vemos o código usado neste evento:

    Private Sub frmPedidos_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'define um datarow para filmes e cartoes
        Dim drLinhaFilmes As DataRow = Nothing
        Dim drLinhaCartao As DataRow = Nothing
        Dim StrConsulta As String
        'define um dataset, sqlcommand e sqldataAdapter
        Dim dsDts As DataSet
        Dim sqlCon As New SqlConnection(strConexaoSQLServer)
        Dim sqlAda As New SqlDataAdapter()
        Dim sqlCmd As New SqlCommand()

        'verifica se houve filmes selecionados
        If intTotalFilmesSelecionados < 1 Then
            'se não selecionou nenhum filme então avisa  e sai
            MessageBox.Show("Não foi selecionando nenhum filme. O formulário de pedidos será fechado ! ", "Selecionar Filme", MessageBoxButtons.OK, 
MessageBoxIcon.Information)
            Me.Close()
        End If

        'exibe o login do cliente no texto do formulário
        Me.Text = Text & " - " & Geral.clienteLogin & " - " & Geral.clienteCodigo.ToString
        strIDFilmesSelecionadosTemp = ""

        For i = 0 To intTotalFilmesSelecionados - 1
            'inclui uma aspa simples 
            strIDFilmesSelecionadosTemp += "'"
            'armazena o id do filme selecionado na string
            strIDFilmesSelecionadosTemp += pedidoFilmesSelecionados.Item(i).Id.ToString()
            'inclui outra aspas simples
            strIDFilmesSelecionadosTemp += "'"
            'se houver mais de um item inclui a virgula para separar
            If i < intTotalFilmesSelecionados - 1 Then
                strIDFilmesSelecionadosTemp += ","
            End If
        Next i

        'define a consulta para procurar o filmeid, titulo,ator,diretor, produto e preco associado com o filme selecionado pelo cliente
        StrConsulta = "SELECT DISTINCT a.FilmeId, a.Titulo, b.Nome AS Ator, c.Nome AS Diretor, d.Nome AS Produtor, f.Preco as Preco FROM Filmes a, Atores b," _
                           + " Diretores c, Produtores d, AtorFilme e, Video f WHERE a.FilmeId = e.FilmeId AND e.AtorId = b.AtorId AND a.DiretorId = c.DiretorId AND a.ProdutorId = 
 d.ProdutorId AND a.FilmeId = f.FilmeId " _
                           + " AND a.FilmeId in (" & strIDFilmesSelecionadosTemp & ")"

        Try
            'cria um novo dataset
            dsDts = New DataSet()
            'define um comando e atribui a conexão associa o  objecto sqladapter com o objeto connection
            sqlAda.SelectCommand = sqlCmd
            sqlAda.SelectCommand.Connection = sqlCon
            'define a consulta armzaenda na varivael strConsulta para ser executada
            sqlAda.SelectCommand.CommandText = StrConsulta
            'preenche a tabela Pedidos no dataset com o resultado da consulta
            sqlAda.Fill(dsDts, "Pedidos")

            'limpa o controle listview antes de exibir
            lvPedidos.Items.Clear()
            'define variavel para calcular o custo total
            Dim dblCustoTotal As Decimal

            'percorre a tabela Pedidos preencheida com os dados da consulta
            For Each drLinhaFilmes In dsDts.Tables("Pedidos").Rows
                'monta uma string com os registros da tabela
                Dim strLinhaFilmes As String() = {drLinhaFilmes(0), drLinhaFilmes(1), drLinhaFilmes(2), drLinhaFilmes(3), drLinhaFilmes(4), drLinhaFilmes(5)}
                'exibe o registro no listview
                lvPedidos.Items.Add(New ListViewItem(strLinhaFilmes))
                'incluir o preco de cada filme calculando o preco total dos filmes
                dblCustoTotal += CDbl(drLinhaFilmes(5))
            Next

            'formata o valor e exibe no formulário
            txtValorTotal.Text = FormatCurrency(dblCustoTotal, 2)
            'especifica  a consulta para retornar os dados do cartão de credito do cliente para o cliente logado
            StrConsulta = "SELECT NumeroCartaoCredito, ValidadeCartao, CodigoSegurancaCartao FROM Clientes  WHERE Login = '" & Geral.clienteLogin & "'"
            'defina a consulta a ser executada
            sqlAda.SelectCommand.CommandText = StrConsulta
            'preenche a tabela CartaoCredito no dataset com o resultado da consulta
            sqlAda.Fill(dsDts, "CartaoCredito")

            'percorre os registros da tabela CartaoCredito
            For Each drLinhaCartao In dsDts.Tables("CartaoCredito").Rows
                'exibe os dados do cartão do cliente no formulário
                txtNumeroCartaoCredito.Text = drLinhaCartao(0)
                txtValidadeCartao.Text = drLinhaCartao(1)
                txtCodigoSeguranca.Text = drLinhaCartao(2)
            Next

        Catch ex As Exception
            'tratamento de erro
            MessageBox.Show("Erro : " & ex.Message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            'libera os objetos usados
            sqlCon.Close()
            sqlAda.Dispose()
        End Try
    End Sub

Este código monta uma string com os IDs dos filmes selecionados - strIDFilmesSelecionadosTemp - obtidos da lista dos filmes que o cliente seleciona no formulário de Pesquisa. Usamos a coleção genérica que foi preenchida com os objetos do tipo Filme definidos na classe Filme :pedidoFilmesSelecionados.Item(i).Id.ToString()

A string será usada na consulta SQL (mostrada a seguir) para obter os dados dos filmes que foram selecionados, e a seguir criamos um dataset com os dados da consulta e exibimos os dados no controle ListView:

'define a consulta para procurar o filmeid, titulo,ator,diretor, produto e preco associado com o filme selecionado pelo cliente
StrConsulta = "SELECT DISTINCT a.FilmeId, a.Titulo, b.Nome AS Ator, c.Nome AS Diretor, d.Nome AS Produtor, f.Preco as Preco FROM Filmes a, Atores b," _
                    + " Diretores c, Produtores d, AtorFilme e, Video f WHERE a.FilmeId = e.FilmeId AND e.AtorId = b.AtorId AND a.DiretorId = c.DiretorId AND a.ProdutorId = d.ProdutorId AND a.FilmeId = f.FilmeId " _
                    + " AND a.FilmeId in ("
& strIDFilmesSelecionadosTemp & ")"

Continuando, geramos outro dataset para obter os dados do cartão de crédito do cliente e preenchemos os controles TextBox do formulário com as informações:

'especifica a consulta para retornar os dados do cartão de credito do cliente para o cliente logado
StrConsulta =
"SELECT NumeroCartaoCredito, ValidadeCartao, CodigoSegurancaCartao FROM Clientes WHERE Login = '" & Geral.clienteLogin & "'"
'defina a consulta a ser executada
sqlAda.SelectCommand.CommandText = StrConsulta
'preenche a tabela CartaoCredito no dataset com o resultado da consulta
sqlAda.Fill(dsDts, "CartaoCredito")

Quando o usuário clicar no botão Finalizar Pedido - devermos gravar as informações nas tabelas Pedidos e DetalhesPedidos concluindo assim o processo.

Abaixo temos o código associado ao evento Click do botão Finalizar Pedido:

Private Sub btnEfetivarPedido_Click(sender As Object, e As EventArgs) Handles btnEfetivarPedido.Click
        Dim strConsulta As String
        Dim intNumeroPedido As Integer
        '
        Dim sqlCon As New SqlConnection(strConexaoSQLServer)
        Dim sqlAda As New SqlDataAdapter()
        Dim sqlCmd As New SqlCommand()
        '
        'chama a função getGeraNumeroPedido que armazena o valor maximo do ultimopedido retornado
        'incrementa o numero do pedido de uma unidade
        intNumeroPedido = getGerarNumeroPedido() + 1

        'define uma consulta para retornar o codigo dos videos para os filmes selecionados
        Dim strSelecao As String = "SELECT MAX(VideoID), COUNT(FilmeId) from Video WHERE FilmeId IN (" & strIDFilmesSelecionadosTemp & ") GROUP BY FilmeId"
        'cria um novo dataset
        Dim DsDataSet As New DataSet
        'atribui a consulta e a conexão ao objeto command
        Dim cmdSeleciona As New SqlCommand(strSelecao, sqlCon)

        Try
            sqlAda.SelectCommand = cmdSeleciona
            'abre a conexão
            sqlCon.Open()
            'preenche a tabela VideoInfo nodataset com o resultado da consulta
            sqlAda.Fill(DsDataSet, "VideoInfo")
        Catch MinhaException As SqlException
            'exibe mensagem de erro
            MessageBox.Show(("Fonte: " & MinhaException.Source & ControlChars.Cr & "Numero: " & MinhaException.Number.ToString() & ControlChars.Cr & _
            "Estado: " & MinhaException.State.ToString() & ControlChars.Cr & "Classe: " & MinhaException.Class.ToString() & ControlChars.Cr & "Server: " 
             & MinhaException.Server & ControlChars.Cr & _
            "Mensagem: " & MinhaException.Message & ControlChars.Cr & "Procedure: " & MinhaException.Procedure & ControlChars.Cr & "Linha: " 
             & MinhaException.LineNumber.ToString()))
            Return
        Finally
            cmdSeleciona.Dispose()
        End Try

        Dim drLinhaVideo As DataRow
        Dim StrVideoLista As String = ""
        Dim strQuantidadeFilmes As String = ""
        Dim nContador As Integer = 0
        'define uma array parra armazenar os videos
        Dim ArrayVideoLista() As String = New String(10) {}

        'percorre a tabela VideoInfo e gera uma string com os codigos dos videos para usar na consulta
        For Each drLinhaVideo In DsDataSet.Tables("VideoInfo").Rows
            If nContador > 0 Then
                StrVideoLista += ","
            End If
            'inclui o codigo do video na string
            StrVideoLista += drLinhaVideo(0).ToString()
            'atribui o codigo do video no array
            ArrayVideoLista(nContador) = drLinhaVideo(0).ToString()
            'incrementa o contador
            nContador += 1
            strQuantidadeFilmes = drLinhaVideo(1)
        Next

        Dim strValorTotalPedido As String
        'define a consulta para calcular o preco total dos filmes do pedido do cliente
        strConsulta = "SELECT SUM(Preco) FROM Video WHERE VideoId IN (" & StrVideoLista & ")"
        'define a consulta a ser executada
        sqlAda.SelectCommand.CommandText = strConsulta
        'preenche a tabela ValorPedido com o resultado da consulta
        sqlAda.Fill(DsDataSet, "ValorPedido")
        'armazena a primeira coluna da primeira linha retornadfa na variavel strValorTotalPedido
        strValorTotalPedido = DsDataSet.Tables("ValorPedido").Rows(0).Item(0)

        Dim strQtdTotal As String
        'define a consulta para calcular o numero de itens do pedido do cliente
        strConsulta = "SELECT COUNT(VideoID) FROM Video WHERE VideoID IN (" & StrVideoLista & ")"
        'define a consulta a ser executada
        sqlAda.SelectCommand.CommandText = strConsulta
        'preenche a tabela QtdTotal com o resultado da consulta
        sqlAda.Fill(DsDataSet, "QtdTotal")
        'armzena a primeira coluna da primeira linha na variavel strQtdtotal
        strQtdTotal = DsDataSet.Tables("QtdTotal").Rows(0).Item(0)

        Dim StrVideoID As String
        Dim j As Integer
        Dim intQuantidadeTotal As Integer
        'define a consulta para incluir os dados na tabela Pedidos
        strConsulta = "INSERT INTO Pedidos (ClienteId, PedidoData, QuantidadeTotal, ValorPedido,NumeroPedido) VALUES (@ClienteID, @PedidoData,
                            @QuantidadeTotal,@ValorPedido,@NumeroPedido); 
                            SELECT PedidoID, ClienteId, PedidoData, QuantidadeTotal,ValorPedido, NumeroPedido FROM Pedidos WHERE NumeroPedido = " & intNumeroPedido
        'cria o objeto command 
        Dim InsertCmdPedidos As New SqlCommand(strConsulta, sqlCon)
        sqlAda.InsertCommand = InsertCmdPedidos
        'associa os parametros com as variaveis e especifica os valores dos parâmetros usados na consulta 
        'clienteid
        sqlAda.InsertCommand.Parameters.Add(New SqlParameter("@ClienteId", System.Data.SqlDbType.Int, 2, "ClienteId"))
        sqlAda.InsertCommand.Parameters(0).Value = Geral.clienteCodigo
        'PedidoData
        sqlAda.InsertCommand.Parameters.Add(New SqlParameter("@PedidoData", System.Data.SqlDbType.Date, 8, "PedidoData"))
        sqlAda.InsertCommand.Parameters(1).Value = Now.Date
        'QuantidadeTotal
        sqlAda.InsertCommand.Parameters.Add(New SqlParameter("@QuantidadeTotal", System.Data.SqlDbType.Int, 2, "QuantidadeTotal"))
        sqlAda.InsertCommand.Parameters(2).Value = Convert.ToInt32(strQtdTotal)
        'ValorPedido
        sqlAda.InsertCommand.Parameters.Add(New SqlParameter("@ValorPedido", System.Data.SqlDbType.Money, 8, "ValorPedido"))
        Dim valorPedido As Decimal = Convert.ToDecimal(strValorTotalPedido)
        sqlAda.InsertCommand.Parameters(3).Value = valorPedido
        'NumeroPedido
        sqlAda.InsertCommand.Parameters.Add(New SqlParameter("@NumeroPedido", System.Data.SqlDbType.Int, 2, "NumeroPedido"))
        sqlAda.InsertCommand.Parameters(4).Value = intNumeroPedido
        Try
            'executa a consulta para incluir os dados na tabela Pedidos
            sqlAda.InsertCommand.ExecuteNonQuery()
            'prepara para gravar os detalhes do pedido na tabela PedidosDeTalhes percorre 
            For j = 0 To nContador - 1
                'pega o id do video no array 
                StrVideoID = ArrayVideoLista(j)
                'armazena a quantidade de filmes na variavel strQuantidadeFilmes
                intQuantidadeTotal = CInt(strQuantidadeFilmes)
                'define a consulta SQL para incluir os dados na tabela PedidosDetalhes
                strConsulta = "INSERT INTO PedidosDetalhes (VideoId, Quantidade, NumeroPedido) VALUES (@VideoId,@Quantidade,@NumeroPedido)"
                'cria o objeto InsertCmdPedidosDetalhes associando-o a consulta e a conexão aberta
                Dim InsertCmdPedidosDetalhes As New SqlCommand(strConsulta, sqlCon)
                'atribui o comando definido ao adapter
                sqlAda.InsertCommand = InsertCmdPedidosDetalhes
                sqlAda.InsertCommand.CommandText = strConsulta
                '
                'associa os parametros com as variaveis e especifica os valores dos parâmetros usados na consulta 
                'VideoId
                sqlAda.InsertCommand.Parameters.Add(New SqlParameter("@VideoId", System.Data.SqlDbType.Int, 2, "VideoId"))
                sqlAda.InsertCommand.Parameters(0).Value = Convert.ToInt32(StrVideoID)
                'Quantidade
                sqlAda.InsertCommand.Parameters.Add(New SqlParameter("@Quantidade", System.Data.SqlDbType.Int, 2, "Quantidade"))
                sqlAda.InsertCommand.Parameters(1).Value = intQuantidadeTotal
                'NumeroPedido
                sqlAda.InsertCommand.Parameters.Add(New SqlParameter("@NumeroPedido", System.Data.SqlDbType.Int, 2, "NumeroPedido"))
                sqlAda.InsertCommand.Parameters(2).Value = intNumeroPedido
                'executa a consulta
                sqlAda.InsertCommand.ExecuteNonQuery()
            Next j
        Catch MinhaException As SqlException
            'tratamento de erros
            MessageBox.Show(("Fonte: " & MinhaException.Source & ControlChars.Cr & _
            "Numero: " & MinhaException.Number.ToString() & ControlChars.Cr & _
            "Estado: " & MinhaException.State.ToString() & ControlChars.Cr & _
            "Classe: " & MinhaException.Class.ToString() & ControlChars.Cr & _
            "Servidor: " & MinhaException.Server & ControlChars.Cr & _
            "Mensagem: " & MinhaException.Message & ControlChars.Cr & _
            "Procedure: " & MinhaException.Procedure & ControlChars.Cr & _
            "Linha: " & MinhaException.LineNumber.ToString()))
            Return
        Finally
            'libera os recursos
            sqlCon.Close()
            sqlAda.Dispose()
        End Try
        'fecha o formulario e exibe mensagem ao cliente
        Me.Close()
        MessageBox.Show("Seu pedido será entregue em 5 dias úteis. Obrigado por ser nosso cliente.", "Pedido", MessageBoxButtons.OK)
    End Sub

Chamamos a função getGerarNumeroPedido() para obter um número de pedido com base nos pedidos já existente. O código desta função é visto a seguir:

Private Function getGerarNumeroPedido() As String

        'define objetos ado net para acesso a dados
        Dim sqlCon As New SqlConnection(strConexaoSQLServer)
        Dim sqlAda As New SqlDataAdapter()
        Dim sqlCmd As New SqlCommand()

        Dim strSelecaoID As String

        'define a consulta para obter o valor maximo do numero do pedido
        strSelecaoID = "SELECT MAX(NumeroPedido) FROM Pedidos"
        Dim SelectCmd As New SqlCommand(strSelecaoID, sqlCon)
        Dim dsDts As DataSet = New DataSet()

        Try
            'define o command, abre a conexão e preenche a tabela PedidosID
            sqlAda.SelectCommand = SelectCmd
            sqlCon.Open()
            sqlAda.Fill(dsDts, "PedidosID")
        Catch MinhaException As SqlException
            'tratamento de erros
            MessageBox.Show(("Fonte: " & MinhaException.Source & ControlChars.Cr & _
            "Numero: " & MinhaException.Number.ToString() & ControlChars.Cr & _
            "Estado: " & MinhaException.State.ToString() & ControlChars.Cr & _
            "Classe: " & MinhaException.Class.ToString() & ControlChars.Cr & _
            "Servidor: " & MinhaException.Server & ControlChars.Cr & _
            "Mensagem: " & MinhaException.Message & ControlChars.Cr & _
            "Procedure: " & MinhaException.Procedure & ControlChars.Cr & _
            "Linha: " & MinhaException.LineNumber.ToString()))
            Return ""
        Finally
            'libera os recursos
            sqlCon.Close()
            SelectCmd.Dispose()
            sqlAda.Dispose()
        End Try
        'percorre a tabela PedidosID e obtem o numero do pedido
        Dim drLinhaPedido As DataRow
        Dim intNumeroPedido As Integer = 1000
        For Each drLinhaPedido In dsDts.Tables("PedidosID").Rows
            'se for o primeiro pedido então atribui o valor 999
            If drLinhaPedido.IsNull(0) Then
                intNumeroPedido = 999
            Else
                'obtem o maior valor do pedido
                intNumeroPedido = drLinhaPedido(0)
            End If
        Next
        'retorna o numero do pedido obtido
        getGerarNumeroPedido = intNumeroPedido
    End Function

O código obtém um dataset com base no maior número de pedido existente: strSelecaoID = "SELECT MAX(NumeroPedido) FROM Pedidos"

Após obter o número do pedido incrementamos o seu valor de uma unidade e criamos um dataset para obter os códigos dos vídeos para os filmes selecionados usando a string que contém os IDs dos filmes:

'define uma consulta para retornar o codigo dos videos para os filmes selecionados
Dim strSelecao As String = "
SELECT MAX(VideoID), COUNT(FilmeId) from Video WHERE FilmeId IN (" & strIDFilmesSelecionadosTemp & ") GROUP BY FilmeId"

A seguir geramos uma nova string contendo os IDs dos vídeos e criamos dois datasets usando consultas SQL com base na string que contém os IDs dos vídeos:

1- O dataset que calcula os preços dos filmes : sqlAda.Fill(DsDataSet, "ValorPedido")

'define a consulta para calcular o preco total dos filmes do pedido do cliente
strConsulta = "SELECT SUM(Preco) FROM Video WHERE VideoId IN (" & StrVideoLista & ")"

2- O dataset que calcula o número de itens no pedido : sqlAda.Fill(DsDataSet, "QtdTotal")

'define a consulta para calcular o numero de itens do pedido do cliente
strConsulta =
"SELECT COUNT(VideoID) FROM Video WHERE VideoID IN (" & StrVideoLista & ")"

Finalmente usando a instrução SQL INSERT INTO incluímos os dados do pedido do cliente na tabela Pedidos e os itens do pedido na tabela PedidosDetalhes.

As consultas usadas são parametrizadas e os parâmetros são incluídos na coleção Parameters onde primeiro definimos o nome do parâmetro (@VideoId), o seu tipo (System.Data.SqlDbType.Int), o tamanho (3) e a qual campo da tabela ele corresponde(VideoId) e depois atribuímos o valor ao parâmetro:Convert.ToInt32(StrVideoID)

sqlAda.InsertCommand.Parameters.Add(New SqlParameter("@VideoId", System.Data.SqlDbType.Int, 3, "VideoId"))
sqlAda.InsertCommand.Parameters(0).Value = Convert.ToInt32(StrVideoID)

Para executar a instrução SQL usamos o método ExecuteNonQuery do objeto Command: sqlAda.InsertCommand.ExecuteNonQuery()

O objeto Command da ADO.NET fornece o método ExecuteNonQuery para executar consultas que não retornam linhas (registros). Apesar de não retornar registros , qualquer parâmetro de saída ou valores retornados mapeados para parâmetros do objeto Comando são preenchidos com dados.

 

O método ExecuteNonQuery retorna o número de linhas afetados pelas operações de Insert , Update e Delete. Para todas as demais consultas o valor retornado é -1.

Quando uma consulta falha na execução o provedor gerenciado dispara uma exceção que você pode capturar no seu código. Os provedores gerenciados ADO.NET possuem classes que fazem o tratamento das exceções. Esta classe de exceção é criada e disparada quando um erro é encontrado.

 

Ao final será exibida uma mensagem ao cliente informando que o pedido foi gravado com sucesso e o prazo para entrega:

 

Na próxima aula do curso iremos tratar do formulário de registros que será usado para cadastrar os clientes na tabela Clientes da base de dados da empresa CiaFilmes.

Referências:


José Carlos Macoratti