VB.NET - Criando uma aplicação em camadas (MVC)


No artigo - Padrões de Projeto : O modelo MVC - Model View  Controller - falei sobre os padrões de projeto , mais especificamente do modelo MVC. Vou mostrar neste artigo um exemplo prático de como podemos criar uma aplicação em 3 camadas , bem próxima do modelo MVC , usando o VB.NET.

Nota: Embora esteja me referindo aqui ao padrão MVC, não estamos implementando realmente esse padrão, mas apenas no baseado no conceito da separação de camadas para implementar uma aplicação em camadas.

Vou criar um projeto do tipo VB.NET com um formulário e um datagrid usando o acesso a dados via DataSet para criar uma aplicação em 3 camadas que permita acessar , alterar e atualizar os dados usando o DataGrid e refletir isto em um DataSet que representa a tabela Customer do banco de dados Northwind.mdb.

O código irá mostrar como enviar novas linhas (registros) , alterar linhas e excluir linhas usando uma camada de serviços que atualiza o banco de dados usando um DataSet. Iremos dividir logicamente nosso projeto em 3 partes :

  1. Camada de apresentação - Contém o código dos formulários Windows - Windows Forms - como o usuário e os serviços de negócios.
  2. Camada de negócios :  Contém o código para os serviços de negócios
  3. Camada de dados : O banco de dados Northwind.mdb - tabela Customer.

A aplicação que irei desenvolver pode ser dividido em dois projetos distintos :

  1. Um projeto baseado em Windows-Forms para apresentar os dados para o usuário
  2. E um projeto do tipo Class Library para gerenciar as regras de negócios e fazer a chamada para manipular os dados. (Os serviços de negócios ficariam responsáveis pelas tarefas de retornar e atualizar os dados na fonte de dados.)

A camada de apresentação -  Windows Forms

Vamos começar com a camada de apresentação. Abaixo temos o formulário do projeto com os seguintes componentes:

- 1 DataGrid - grdData

- 3 Buttons - Button1 , Button2  e Button3

O componente DataGrid irá exibir os dados ao usuário e os botões irão ter as seguintes funcionalidades :

  • Carregar Dados - carrega o DataSet com dados da tabela e exibe
  • Salvar Dados - Salva as alterações no Dataset
  • Sair - sai da aplicação.

Por que estou usando um DataGrid ? Bem...

O DataGrid é um controle de Servidor que pode ser facilmente manipulado para renderizar um conjunto de registros pela vinculação com  um DataSet.

Você deve estar meio desconfiado e deve também estar duvidando que é possível criar uma aplicação 3 camadas da forma com eu estou fazendo. Com certeza ao ler que eu vou vincular o DataSet ao DataGrid você pode até pensar que a vinculação será feita feita como nos velhos tempos do VB6.

Calma !!! No mundo .NET vincular tem um sentido muito diferente. Quando um DataSet é vinculado a um DataGrid , os dados do DataSet são copiados para o DataGrid. As alterações feitas nos dados do DataGrid são então repassadas para o DataSet para refletir as  mundaças. Qual a diferença ???  Vou explicar ...

Quando você usava o VB6 e a ADO (lembra ???) as técnicas de vinculação de dados envolviam vincular os dados do Grid diretamente a um controle Data e dai para o banco de dados. Neste esquema a conexão com o banco de dados fica aberta o que limita muito nossa aplicação pois você tem a camada de apresentação diretamente ligada com a camada de dados.

Com o VB .NET temos o grid ainda vinculado ao DataSet , mas o DataSet não tem uma conexão com o banco de dados. Na verdade o DataSet nem mesmo sabe ou se importa em saber de onde os dados estão vindo. O DataSet pode ser preenchido com dados a partir de uma variedade de fonte de dados e até mesmo se preenchido manualmente sem fonte de dados alguma. Ai que esta a diferença...

Quando o usuário altera os dados no DataGrid do formulário, as mudanças são enviadas ao DataSet de forma automática. Qualquer nova linha de registro incluída é também incluída no DataSet e qualquer linha alterada é atualizada no DataSet. Linhas excluídas do DataGrid são removidas do DataSet (elas são marcadas como excluídas).

O DataSet trata todas as mudanças nos dados  armazenando o valor original e atual de cada linha e coluna. Assim , se um DataGrid contiver 1000 linhas de dados e o usuário alterar 3 linhas, incluir 1 nova linha e excluir outras 2 linhas, as linhas afetadas podem ser extraíadas do DataSet vinculado para outro DataSet de maneira que o novo DataSet irá conter somente estas 6 linhas alteradas.

A seguir o código da classe frmMain :  Aqui temos a classe frmMain onde a variável m_oDS representa o DataSet. 

Public Class frmMain

Inherits System.Windows.Forms.Form

'//----------------------------------------------------------------------------------------------------

'// Declara variável de class

'//----------------------------------------------------------------------------------------------------

Private m_oDS As DataSet

 

'//----------------------------------------------------------------------------------------------------

'// Retorna e carrega os dados para o formulário

'//----------------------------------------------------------------------------------------------------

Private Sub LoadData()

   Dim oCustomer As BusinessServices.Customer = New BusinessServices.Customer()

   grdData.DataBindings.Clear()

   m_oDS = oCustomer.GetData()

   grdData.DataSource = m_oDS.Tables("Customer")

   oCustomer = Nothing

End Sub

'//------------------------------------------------------------------------------------------------------------

'// Envia os dados alterados para os serviços de negócios

'//------------------------------------------------------------------------------------------------------------

Private Sub SaveData()

 

Dim lRetVal As Long

Dim oCustomer As BusinessServices.Customer = New BusinessServices.Customer()

Dim oDS_Delta As DataSet

Dim sMsg As String

'//--- Verifica se houve alterações

   If m_oDS Is Nothing Then Exit Sub

      If Not m_oDS.HasChanges() Then Exit Sub

       '//--- Trata todas as mudanças

       oDS_Alterados = m_oDS.GetChanges()

       sMsg = "Esta certo que quer salvar   " & oDS_Alterados.Tables(0).Rows.Count() & "  linhas da fonte de dados ? "

       lRetVal = MsgBox(sMsg, Microsoft.VisualBasic.MsgBoxStyle.Question + Microsoft.VisualBasic.MsgBoxStyle.YesNo, "Salva Dados")

       Select Case lRetVal

           Case vbYes

              Try

                 '//--- Salva todas as alterações

                 sMsg = oCustomer.SaveData(oDS_Alterados)

                 LoadData()

             Catch e As Exception

                 sMsg = "Erro ao salvar dados." & vbCrLf & vbCrLf & e.Message.ToString()

             Finally

                  MsgBox(sMsg, Microsoft.VisualBasic.MsgBoxStyle.Information, "Salva Dados")

             End Try

        Case vbNo

             '//--- Nada

      End Select

  oDS_Delta = Nothing

  oCustomer = Nothing

End Sub

 

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

   LoadData()

End Sub

 

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

   SaveData()

End Sub

 

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

   Me.Dispose()

End Sub

 

End Class

- Quando o usuário clicar no botão - Carregar Dados - o método LoadData() será invocado . Nele estamos declarando e criando uma instância da classe serviços de negócios :

Dim oCustomer As BusinessServices.Customer = New BusinessServices.Customer()

- A seguir declaramos a vinculação de dados e iniciamos com o status clear (limpo). Então usamos o método GetData do objeto de serviços de negócios - oCustomer - para retornar o DataSet preenchido com os dados da tabela - Customer - para o formulário através do DataGrid. Feito isto o DataSet será local e estará vinculado ao DataGrid.

   grdData.DataBindings.Clear()

   m_oDS = oCustomer.GetData()

   grdData.DataSource = m_oDS.Tables("Customer")

   oCustomer = Nothing

- Com os dados preenchendo o DataGrid e sendo exibidos no formulário o usuário poderá interagir com os dados via interface : alterando , excluindo e incluindo novos registros. Para salvar as alterações o usuário irá clicar no botão - Salvar Dados - que irá invocar o método SaveData().

- O método SaveData() cria uma instância dos objetos de serviços - BusinessServices.Customer() - e verifica se houve qualquer alteração nos dados usando o método HasChanges(). Como o DataSet esta vinculado ao DataGrid qualquer alteração feita será refletida no DataSet. Havendo alterações eu utilizo a variável   oDS_Alterados para armazenar os registros alterados :        oDS_Alterados = m_oDS.GetChanges()

- O método GetChanges do DataSet copia as linhas alteradas do DataSet e as coloca em um novo DataSet: oDS_Alterados.

- Finalmente o usuário deverá confirmar se deseja salvar as alterações

A camada de serviços

A camada de serviços é definida em uma classe chamada : BusinessServices.  O código da classe esta descrito a seguir :

'//--------------------------------------------------------------------------------------------------------

'// Declara todos os NameSpaces que serão referenciados

'//--------------------------------------------------------------------------------------------------------

Imports System

Imports System.Data

Imports System.Data.OleDb

'//--------------------------------------------------------------------------------------------------------------

'// NameSpace BusinessServices

'//--------------------------------------------------------------------------------------------------------------

Namespace BusinessServices

Public Class Customer

 

'//----------------------------------------------------------------------------------------------------

'// Declara as variáveis de Classe

'//----------------------------------------------------------------------------------------------------

Private m_sProvider As String = "PROVIDER=Microsoft.Jet.OLEDB.4.0;"

Private m_sServer As String = "DATA SOURCE=C:/teste/" '

Private m_sDatabase As String = "Northwind1.mdb"

Private m_oDS As DataSet

Private m_oCn As OleDbConnection

Private m_oDA As OleDbDataAdapter

Private m_sClassName As String = "Customer" '//--- o nome da classe

'//----------------------------------------------------------------------------------------------------

'// Constructor (sem argumentos)

'//----------------------------------------------------------------------------------------------------

Sub New()

Dim sSQL As String = ""

Dim oSelCmd As OleDbCommand

Dim oInsCmd As OleDbCommand

Dim oUpdCmd As OleDbCommand

Dim oDelCmd As OleDbCommand

'---------------------------------------------------------

'--- define a conexao

'---------------------------------------------------------

InitializeConnection()

'---------------------------------------------------------

'--- define o SELECT Command

'---------------------------------------------------------

sSQL = "SELECT CustomerID, CompanyName, ContactName, City, Region FROM Customers ORDER BY CompanyName "

 

oSelCmd = Nothing

oSelCmd = New OleDbCommand(sSQL, m_oCn)

oSelCmd.CommandType = CommandType.Text

'---------------------------------------------------------

'--- define o UPDATE Command

'---------------------------------------------------------

sSQL = "UPDATE Customers " & _

" SET CompanyName = @CompanyName , ContactName = @ContactName, City = @City, Region = @Region WHERE CustomerID = @CustomerID "

 

oUpdCmd = Nothing

oUpdCmd = New OleDbCommand(sSQL, m_oCn)

 

With oUpdCmd

   .CommandType = CommandType.Text

   With .Parameters

      .Add(New OleDbParameter("@CompanyName", OleDbType.VarChar, 40, "CompanyName"))

      .Add(New OleDbParameter("@ContactName", OleDbType.VarChar, 30, "ContactName"))

      .Add(New OleDbParameter("@City", OleDbType.VarChar, 15, "City"))

      .Add(New OleDbParameter("@Region", OleDbType.VarChar, 15, "Region"))

      .Add(New OleDbParameter("@CustomerID", OleDbType.LongVarChar, 5, "CustomerID"))

   End With

End With

'---------------------------------------------------------

'--- define o INSERT Command

'---------------------------------------------------------

sSQL = "INSERT INTO Customers " & _

" (CompanyName, ContactName, City, Region, CustomerID) VALUES (@CompanyName, @ContactName, @City, @Region, @CustomerID)"

oInsCmd = Nothing

oInsCmd = New OleDbCommand(sSQL, m_oCn)

 

With oInsCmd

   .CommandType = CommandType.Text

    With .Parameters

     .Add(New OleDbParameter("@CompanyName", OleDbType.VarChar, 40, "CompanyName"))

     .Add(New OleDbParameter("@ContactName", OleDbType.VarChar, 30, "ContactName"))

     .Add(New OleDbParameter("@City", OleDbType.VarChar, 15, "City"))

     .Add(New OleDbParameter("@Region", OleDbType.VarChar, 15, "Region"))

     .Add(New OleDbParameter("@CustomerID", OleDbType.LongVarChar, 5, "CustomerID"))

    End With

End With

'---------------------------------------------------------

'--- define o DELETE Command

'---------------------------------------------------------

sSQL = "DELETE Customers WHERE CustomerID = @CustomerID "

oDelCmd = Nothing

oDelCmd = New OleDbCommand(sSQL, m_oCn)

With oDelCmd

    .CommandType = CommandType.Text

    With .Parameters

       .Add(New OleDbParameter("@CustomerID", OleDbType.LongVarChar, 5, "CustomerID"))

     End With

End With

'---------------------------------------------------------

'--- cria e define os comandos para o DataSet

'---------------------------------------------------------

m_oDA = New OleDbDataAdapter()

With m_oDA

  .SelectCommand = oSelCmd

  .UpdateCommand = oUpdCmd

  .DeleteCommand = oDelCmd

  .InsertCommand = oInsCmd

End With

'//--- Destroi o objeto connection

m_oCn = Nothing

End Sub

'//------------------------------------------------------------------------------------------------------------

Public Function SaveData(ByVal oDS As DataSet) As String

 

Dim sMsg As String

Dim lRecsAffected As Long

Dim oTran As OleDb.OleDbTransaction

'---------------------------------------------------------

'//--- Salva os dados

'---------------------------------------------------------

Try

'--- define a conexao

InitializeConnection()

   m_oCn.Open()

   '--- inicia a transacao

   oTran = m_oCn.BeginTransaction()

   '--- atualiza o banco de dados

   lRecsAffected = m_oDA.Update(oDS, m_sClassName)

    '--- consolida (commit) as mudanças

    oTran.Commit()

   '--- define as mensagens para o usuario

   sMsg = lRecsAffected & " registros foram atualizados"

   Catch e As Exception

        '--- Ocorreu um erro Desfaz a transacao

       oTran.Rollback()

       sMsg = "Os registros não foram atualizados." & vbCrLf & e.Message.ToString()

   Finally

'--- Fecha a conexao

oTran = Nothing

m_oCn.Close()

m_oCn = Nothing

SaveData = sMsg

End Try

End Function

'//------------------------------------------------------------------------------------------------------------

// retorna os dados da tabela clientes

'//------------------------------------------------------------------------------------------------------------

Public Function GetData() As DataSet

  '--- Cria um novo datase

  m_oDS = New DataSet()

   '--- preenche o dataset com os dados dos clientes

  m_oDA.Fill(m_oDS, m_sClassName)

  '//--- Retorna o dataset

  Return m_oDS

End Function

 

'//------------------------------------------------------------------------------------------------------------

'// Inicializa a conexão

'//------------------------------------------------------------------------------------------------------------

Private Sub InitializeConnection()

  '--- define a conexao

  m_oCn = New OleDbConnection(m_sProvider & m_sServer & m_sDatabase)

End Sub

 

End Class

End Namespace

 

A camada de acesso a dados vai ser discutida em outros artigos sobre o tema mas creio que deu para dar uma visão geral sobre o assunto.

Aguarde mais artigos sobre o tema em breve  ...

Eu sei é apenas VB .NET mas eu gosto:

    Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter


Referências:


José Carlos Macoratti