ADO.NET - Criando um Cadastro de Clientes
Objetivo: Nosso objetivo será gerenciar as informações de clientes em um banco de dados Access usando ADO.NET e implementar as operações de Incluir , Excluir , Alterar e habilitar a navegação pelos registros.O código completo deste artigo esta no Super CD .Net.
Antes de iniciar este projeto você vai precisar criar um local onde você vai salvar seu projeto. Rode o Visual Studio .NET ou o Visual Basic .NET e no menu File selecione a opção New... ; a seguir selecione a opção Blank Solution :
A janela New Project irá surgir . Nela você pode digitar o seu nome (ou qualquer nome que queira informar) na caixa de texto Name e deixar todas as demais configurações com seus valores padrões.
A seguir click no botão OK. Ao terminar uma pasta chamada Macoratti (ou seu nome) será criada no interior da pasta D:\vbnet.
Agora que você terminou de criar uma solução em branco (Blank Solution) , no menu File , selecione a opção Add Project e a seguir New Project ..
Na janela Add New Project selecione em Project Types : Visual Basic Projects e em Templates : Windows Application. A seguir informe o nome do projeto na caixa de texto Name. (chamei o projeto de VisualizaDados). Com isto você estará criando uma nova pasta dentro de d:\vbnet\macoratti com o nome do projeto informado.
Vamos alterar o nome do formulário padrão - form1.vb - criado na Solução. Selecione o formulário form1.vb e na janela Properties procure a propriedade File Name . Informe a seguir o novo nome do formulário - frmDados.vb. (não esqueça de informar a extensão .vb)
Agora vamos alterar as propriedades Name e Text do formulário - FrmDados.vb. Para exibir as propriedades do formulário apenas clique no formulário a seguir altere o valor da propriedade Text para - Cadastro de Clientes e o valor da propriedade Name para frmdados.
Podemos agora definir o o Startup Object , ou seja o formulário que será executado quando sua aplicação for executada. Clique com o botão direito do mouse no projeto VisualizaDados na janela Solution Explorer e a seguir clique no item Properties do menu. A janela - Visualiza Property Pages irá aparecer:
Em Statup object selecione - frmDados. Deixe as demais propriedades com o valor padrão.
Incluindo um controle Data Adapter no formulário
Abra a janela ToolBox (se a janela não estiver visível clique no menu View e a seguir em ToolBox) e clique no botão Data para exibir os controles de dados que iremos usar no projeto conforme abaixo.
- Em nosso projeto iremos criar e acessar
uma base de dados Access ; por isto vamos usar os
controles de dados OleDB. (Se formos acessar
uma base de dados SQL Server devemos usar os controles SQL). - Um Data Adapter é parte integral dos provedores gerenciados ADO.NET que fornecem um conjunto de objetos usados para realizar a comunicação entre a fonte de dados (um banco de dados) e um DataSet(na sua aplicação). - Isto permite a você ler dados do banco de dados para o interior do seu DataSet e escrever as alterações do DataSet para o Banco de dados. - Ao incluir o Data Adapter no seu formulário o assistente de configuração Data Adapter irá conduzí-lo através do processo de configuração do Data Adpater. - Como vamos usar um banco de dados Access insira um controle OledbDataAdpater no seu formulário. |
O assistente de configuração para o Data Adapter: Ao surgir a primeira tela do Assistente clique no botão Next>
- Vou realizar uma conexão com o banco de
dados Biblio.mdb e nele acessar e gerenciar dados
da tabela Clientes cuja estrutura é a seguinte:
|
Na próxima janela clique no botão - New Connection ; Isto vai abrir a janela - Data Link Properties ; Clique na aba - Provider - e selecione : Microsoft Jet 4.0 OLE DB Provider. Isto vai permitir a conexão com um banco de dados Microsoft Access.
Existem uma lista de provedores com o qual podemos realizar conexões com diferentes tipos de banco de dados ; SQL Server , Oracle , etc... Agora clique no botão - Next >> para irmos para a janela propriedades da vinculação de dados:
- Na aba Connection é onde definimos um banco de dados . Clique no botçao ... e selecione o banco de dados. Vou selecionar o banco de dados Biblio.mdb - Apos selecionar o banco de dados clique no botão - Test Connection para verificar se a ligação com o banco de dados esta funcionando. Se tudo estiver OK deveremos ver a janela: Clique no botão OK da janela de teste de conexão - Data Link Clique em OK na janela - Data Link Properties Para prosseguir clique no botão Next> do Assistente de configuração. |
a próxima janela de diálogo permite a você escolher uma consulta. Selecione Use SQL statements e clique no botão Next>
Simple Query Language ou SQL. Na próxima janela precisamos definir o comando SQL que deverá conter o nome da tabela e os campos da tabela que desejamos acessar e exibir em nosso programa. O formato da instrução SQL para seleção de dados é :
SELECT <campos> FROM <nome Tabela>
Na janela podemos digitar a instrução diretamente ou usar o Query Builder para ajudar-nos a criar esta instrução. Click no botão - Query Builder - .
A janela - Add Table - exibe uma lista com todas as tabelas que nosso banco de dados - Biblio.mdb contém. Selecione a tabela Clientes e clique no botão - Add ; a seguir clique no botão - Close - . A janela do Query Builder irá ter a seguinte aparência conforme a janela abaixo:
- Marcamos os campos que desejamos
exibir na consulta - Endereco, ID, Nascimento ,
Nome , Telefone e UF - Clicando no botão OK teremos a consulta montada e exibida na janela - Query Builder -: |
A seguir temos a janela com a consulta SQL montada :
Se você clicar no botão - Advanced Options - teremos a tela abaixo. As opções Generate insert, update and Delete statements permite a você implementar as funcionalidades de edição de dados em seu programa.(Se a tabela for aberta apenas para consulta você não precisará desses recursos).
O item - Use optimistic concurrency - o ajuda a manter a integridade dos dados com a tabela. Deixe estas opções marcadas e clique no botão OK ; a seguir no botão - Finish do assistente.
Após encerrar o Assistente os componentes Data Adapter(OleDbDataAdapter1) e Connection(OleDbConnection1) serão exibidos no seu projeto.
O objeto
connection é criado automaticamente quando
incluimos o DataAdapter. A objeto connection atual
contém todas as informações sobre o provedor. O DataAdapter contem a propriedade SelectCommand.CommandText que armazena a instrução SQL - Select - . ( Um data adapter precisa de uma conexão aberta com a fonte de dados para ler e escrever dados por isto o data adapter utiliza um objeto connection para se comunicar a fonte de dados. |
Vamos alterar o nome destes componentes. Clique no OleDbDataAdapter1 e na janela de propriedades altere o seu nome para : odaClientes . Altere o nome da conexão para odcClientes.
Gerando um objeto DataSet
Clique com o botão direito do mouse sobre o objeto odaClientes e selecione a opção : Generate Dataset
Um
DataSet armazena dados no modo desconectado (um cache no
seu computador local). A estrutura de um dataset é
idêntica a um banco de dados relacional, i.e, ele expõe
um modelo de objeto hierárquico de tabelas,
registros(linhas) e campos(colunas). Ele também contém
relacionamentos e restrições definidas no dataset. Nota - Como um data é um container desconectado para dados ( diferente do objeto recordset da ADO) ele não precisa suporta o conceito de registro atual. Ao invés todos os registros no dataset estão disponíveis. Como não registro atual não existe uma propriedade específica que aponta para o registro atual e não há métodos ou propriedades para a movimentação de um registro para outro. ( Em um recordset ADO temos as propriedades movefirst, movenext , moveprevious, movelast e AbsolutePosition, etc..) Em um dataset você acessa tabelas individuais como objetos ; cada tabela expoõe uma coleção de linhas (registros) e você acessa os registros via indice da coleção ou usa um comando específico da coleção no seu código. |
Na janela para gerar o DataSet clique em New e informe o nome do DataSet - dsClientes. A seguir clique no botão OK.
Note que foi gerado no seu projeto o objeto dsClientes1 . Altere o seu nome para dsClientes conforme a figura abaixo:
Com isto completamos a inclusão dos componentes necessários para acessar o banco de dados Access. Então em nosso projeto temos até o momento:
Podemos dar uma olhada nos dados da tabela Clientes. Para isto clique com o botão direito do mouse sobre o objeto odaClientes e selecione a opção - Preview Data.... A janela - Data Adapter Preview - será exibida , e se você clicar em - Fill DataSet - os dados da tabela clientes serão exibidos conforme abaixo:(Você não pode editar registros nesta janela)
Criando o formulário para exibir os dados
Vamos agora incluir no formulário padrão - frmDados.vb - os controles para poder exibir os dados e efetuar a movimentação pelos registros. Vamos usar controles Labels , TextBox , e Buttons. Na figura abaixo temos o layout do formulário já pronto.
O formulário tem sua propriedade Text definida para : Cadastro de Clientes e sua propriedade Icon definida para o ícone exibido. |
-Para os controles
Labels vamos usar o nome padrão e
alterar somente a propriedade Text para exibir o nome da
etiqueta. (no VB.NET o controle label não possui mais
a propriedade Caption). -Para os controles TextBox vamos alterar a propriedade Name de cada um conforme abaixo: - TxtID , TxtNome, TxtEndereco, TxtTelefone , TxtUF e TxtNascimento - Os controles buttons também terão a propriedade Name alterada conforme abaixo: - Os botões de movimentação: btnInicio, btnAnterior, btnProximo e btnFim - Os botões de operação : btneditar, btnsalvar , btncancela, btnincluir e btnexcluir |
Uma propriedade interessante em modo de desenho do formulário é que podemos visualizar a ordem de tabulação dos controles ; basta selecionar no menu View a opção Tab Order .
- Ao lado temos exibido a ordem de
tabulação de cada controle. - Para alterar basta clicar sobre o número . Cada clique incrementa o valor de uma unidade até chegar ao último valor. |
Vinculando os controles ao DataSet
Vamos vincular os controles TextBox (é o único no qual vamos exibir os dados) ao DataSet. Vamos começar com o controle TxtID que irá exibir o código do cliente. Selecione o textbox txtID e a seguir na janela de propriedades expanda a propriedade DataBindings.
- Em
DataBindings selecione - Text e a seguir clique
na caixa ao lado para que a relação de campos da tabela
clientes do DataSe seja exibida. - Marque o campo ID Repita a operação para os demais campos TextBox selecionando em cada um deles o campo apropriado que deseja exibir. |
Exibindo os registros nos controles vinculados
Para podermos visualizar os registros nos campos textos vinculados devemos preencher o DataSet. Fazemos isto inserindo o seguinte código no evento Load do formulário. (para ativar o evento Load basta clicar duas vezes no formulário)
'Limpamos o Dataset antes de preenchê-lo!
dsClientes.Clear()
'O método Fill do Data Adapter preenche o data set ligado a ele.
odaClientes.Fill(dsClientes, "Clientes")
Se você rodar o projeto agora terá os dados exibidos no formulário. Antes de fazer isto vamos incluir os botões de navegação para permitir que possamos nos movimentar pelos registros.
Em cada botão alteramos a propriedade Name e a propriedade Image na qual vinculamos imagens de seta para cada funcionalidade de movimentação. Clicando duas vezes no botão - btnProximo - teremos ativado o evento Click ,nele inserimos o seguinte código:
'Incrementa a
propriedade Position do BindingContext
para se mover para o próximo registro,
' No primeiro registro o valor de Position
é igual a zero.
Me.BindingContext(dsClientes,
"Clientes").Position += 1
Agora vamos a um pouco de teoria para explicar como isto funciona. Afinal para que serve esse tal de BindingContext.
Qualquer fonte de dados que você vincula a um formulário ou controle container (picture box,group box, etc.) será associado ao objeto CurrencyManager.
O objeto CurrencyManager gerencia a posição e também supervisiona as vinculações a fonte de dados. Existe um objeto CurrencyManager no formulário para cada fonte de dados que você vincula a ele. Se todos os controles do formulário estiverem vinculados a uma única fonte (Ex: Varios TextBox vinculados a mesma tabela como no nosso projeto) então eles irão compartilhar o mesmo objeto CurrencyManager.
Há momentos , porém, quando os controles no formulário estarão vinculados a fonte de dados distintas. Neste caso haverá múltiplos objetos CurrencyManager no formulário, cada um gerenciando o registro ou dado que esta sendo usado pelo controle. Isto pode se tornar um pouco confuso. É ai que entra o objeto BindingContext. Cada formulário Windows possui um objeto BindingContext.
O objeto BindingContext gerencia todos os objetos CurrencyManager no formulário e ajuda nos a navegar , incluir , excluir e editar registros em uma tabela. Então estamos usando o objeto BindingContext para fazer as seguintes tarefas:
Com isto em mente vamos mostrar o código usado para os demais botões de movimentação de registros: (Todos os códigos estão inseridos no evento Click da cada botão:)
1- ) Botão que vai para o registro Anterior: btnProximo
'Incrementa a
propriedade Position property do objeto BindingContext
para mover um registro para frente.
Me.BindingContext(dsClientes,
"Clientes").Position
+= 1
2-) Botão que vai para o registro anterior: btnAnterior
'Decrementa a
propriedade Position property do objeto BindingContext
para mover um registro para trás.
Me.BindingContext(dsClientes,
"Clientes").Position -= 1
3-) Botão que vai para o primeiro registro: btnInicio
'Define a
propriedade Position do objeto
BindingContext para 0 (vai par o primeiro registro)
Me.BindingContext(dsClientes,
"Clientes").Position
= 0
4-) Botão que vai para o último registro: btnFim
'A
propriedade Count property do objeto BindingContext
é igual o número de registros na tabela.
' Definindo a propriedade Position do BindingContext
para Count - 1 vamos para o último
registro
Me.BindingContext(dsClientes,
"Clientes").Position
= Me.BindingContext(dsClientes,
"Clientes").Count - 1
Podemos executar a aplicação para ter uma visão do seu aspecto. Abaixo temos o formulário exibindo os dados e os botões de navegação.(as demais funcionalidades iremos abordar adiante...)
Habilitando e desabilitando os botões de navegação
Para tornar nossa aplicação mais interativa precisamos incluir as seguintes funcionalidades:
Para incluir tais funcionalidades vamos usar o seguinte código:
'Quando a propriedade Position é igual a propriedade Count menos 1 (-1) alcançamos o último registro
' Vamos desabilitar os botões btnProximo e btnFim.
If Me.BindingContext(dsClientes, "Clientes").Position = Me.BindingContext(dsClientes, "Clientes").Count - 1 Then
btnProximo.Enabled = False
btnFim.Enabled = False
Else 'Senão habilita os botões btnProximo e btnFim.
btnProximo.Enabled = True
btnFim.Enabled = True
End If
O código abaixo habilita de desabilita os botões btnAnterior e btnInicio:
'WQuando a propriedade Position for igual a 0 chegamos no ínicio do da tabela
' então disabilitamos os botões btnAnterior e btnInicio.
If Me.BindingContext(dsClientes, "Clientes").Position = 0 Then
btnAnterior.Enabled = False
btnInicio.Enabled = False
Else 'Senão habilitamos os botões PbtnAnterior e btnInicio .
btnAnterior.Enabled = True
btnInicio.Enabled = True
End If
Já temos o código mas onde devemos colocá-lo ? e quando o código deverá se executado ?
- Bem , o código deverá ser executado sempre que o registro atual mudar. Ao mudar para um registro diferente , nos modificamos o valor da propriedade Position no evento Click em cada botão de navegação , Lembra-se ?
Então , nos podemos criar uma rotina que contenha código acima e ela deverá ser chamada em cada botão de navegação. Certo ? Sim , mas podemos fazer algo mais elegante...
Criando um procedimento Delegado com a declaração addHandler
Um procedimento Delegado (Delegate) é uma rotina que nos criamos e que é chamada automaticamente quando um evento normal é disparado. Então ao invés de ficar fazendo várias chamadas para a nossa rotina podemos criar um procedimento delegate que irá ser chamado automaticamente sempre que a propriedade Position sofre alterações.
"Delegate" ou Delegado é o nome usado para descrever um procedimento em VB.NET que permite a você controlar o código que atualmente manipula um evento. (Como um evento Change , Click , Load , etc.). Um delegate é então uma classe que pode manipular uma referência um método.
È fácil fazer isto com a declaração - AddHandler . Para tornar isto funcional vamos criar uma rotina delegada contendo o código acima. Fazemos a seguinte declaração :
Private Sub SetButtons(ByVal sender As Object, ByVal e As EventArgs)
Para a rotina SetButtons ser um procedimento delegado , ele deve incluir um sender especial e parâmetros e que um evento normal tenha passado para a rotina pelo sistema operacional.
A estrutura de uma rotina delegate e de uma rotina event tem isto em comum. mesmo se nós não formos usar os valores nestes parâmetros no nosso código na rotina SetButtons eles precisam ser incluídos para a rotina ser considerada delegada.
Vamos criar uma região na nossa janela de código de forma a poder localizar mais facilmente o código criado. Na janela de código localize a linha End Class e na linha abaixo digite o seguinte código:
#Region "Procedimentos Personalizados"
Um linha #End Region será incluída de forma automática. Dentro desta região vamos digitar a linha de código abaixo para criar a rotina SetButtons:
Private Sub SetButtons(ByVal sender As System.Object, ByVal e As System.EventArgs)
Termina de digitar o restante do código abaixo:
Private Sub
SetButtons(ByVal
sender As
System.Object, ByVal
e As
System.EventArgs)
End Sub |
Agora para tornar a rotina SetButtons uma rotina Delegate (que será executada sempre que a propriedade Position de Me.BindingContext mudar - vamos usar a declaração - AddHandler. Assim :
AddHandler <event> AddressOf <delegate procedure>
Onde:
Agora nós precisamos encontrar um procedimento de evento que seja disparado sempre que a propriedade Position mudar. Vamos usar o procedimento de evento PositionChanged da classe BindingManagerBase.
Nota: A classe BindingManagerBase permite a sincronização de todos os controles vinculados em um formulário Windows vinculados a uma mesma fonte de dados. É uma classe abstrata e é intrínseca a todo o projeto que você cria. É por isto que estamos usando uma rotina delegada. Não temos acesso pois os procedimentos de uma classe abstrata não estão acessíveis.
Como a classe BindingManagerbase é abstrata nos precisamos criar uma instância dela para acessar o seu procedimento de evento PositionChanged para fornecer ao parâmetro <event> da nossa declaração AddHandler. Para isto inclua o seguinte linha de código no evento Load do formulário frmDados:
Dim bmClientes As BindingManagerBase = Me.BindingContext(dsClientes, "Clientes")
Agora podemos fornecer o parêmetro <event> a declaração AddHandler. Fazemos isto assim:
AddHandler bmClientes.PositionChanged, AddressOf SetButtons
Isto torna nossa rotina SetButtons uma rotina delegada que irá ser chamada automaticamente sempre que o evento PositionChanged da classe BindingManagerBase for disparado .
Antes de testar a aplicação e os botões de navegação dos registros precisamos fazer um ajuste para que quando o programa seja iniciado. Quando o programa for executado pela primeira vez a propriedade Position do objeto BingindContext não estará sofrendo alterações a rotina SetButtons não será invocada. Para forçar isto devemos colocar o seguinte código no evento Load do formulário:
'Quando o programa inicia a propriedade Position não é alterada.
' Para forçar isto precisamos fazer uma chamada manual a rotina
SetButtons(sender, e)
Exibindo o total de registro e o número do registro atual
Que tal se pudéssemos exibir o total de registro em relação ao registro atual da base de dados ? Moleza...
Vamos incluir 3 Labels para poder identificar estas informações , e, defina as propriedades das labels conforme abaixo:
label - lblreg | label : lblde | label : lbltotal | |||
Property | Valor | Property | Value | Property | Valor |
Text | "" | Text | de | Text | "" |
Name | lblreg | Name | lblde | Name | lblTotal |
Vamos inserir o código que exibe o total de registros na label - lblTotal e o código que exibe o registro atual na label - lblreg. Digite o código abaixo na rotina SetButtons (poderiamos ter incluido no evento Load e em cada evento Click dos botões de navegação)
lblReg.Text = Me.BindingContext(dsClientes, "Clientes").Position + 1
'A propriedade Count de BindingContext é sempre igual ao número total de registros
lblTotal.Text = Me.BindingContext(dsClientes, "Clientes").Count
Incluindo, alterando e excluindo dados
Vamos agora implementar as rotinas de inclusão , alteração e exclusão de dados e as rotinas para cancelar uma operação e Salvar os dados na fonte de dados. Estas funcionalidades possuem o código associado ao evento Click dos botões : Editar , Salvar , Cancela , Incluir e Excluir.
Como o código esta comentado vou apenas exibir o código de cada botão e destacar a linha de código principal.. Abaixo temos os códigos :
Código para Incluir um registro | |
Private
Sub BtnIncluir_Click(ByVal
sender As System.Object, ByVal e
As System.EventArgs) Handles
BtnIncluir.Click
iPosicaoReg = Me.BindingContext(dsClientes, "Clientes").Position
'O método AddNew do objeto BindingContext inclui um novo registro (linha) na tabela Me.BindingContext(dsClientes, "Clientes").AddNew()
End Sub |
|
Código para Editar um registro | |
Private
Sub btneditar_Click(ByVal
sender As System.Object, ByVal e
As System.EventArgs) Handles
btneditar.Click
'desabilita o botão de navegação para forcar o usuario a completar o processo de edicao btninicio.Enabled = False btnanterior.Enabled = False btnproximo.Enabled = False btnfim.Enabled = False 'define as propriedades ReadOnly dos textboxes para False para nao permitir edicao txtNome.ReadOnly = False txtEndereco.ReadOnly = False txtUF.ReadOnly = False txtNascimento.ReadOnly = False txtTelefone.ReadOnly = False 'poe o foco no textobx nome txtNome.Focus() End Sub
|
|
Código para Excluir um registro |
|
Private
Sub
btnexcluir_Click_1(ByVal
sender As System.Object, ByVal e
As System.EventArgs) Handles
btnexcluir.Click Dim iResponse As Integer 'sempre confirmar a exclusao de um registro pois ela não tem retornoiResponse = MessageBox.Show("Confirma a exclusção deste registro ?", _ "Confirma Exclusão", MessageBoxButtons.YesNo, MessageBoxIcon.Question) If iResponse = vbYes Then 'usei o método RemoveAt para excluir o registro Me.BindingContext(dsClientes, "Clientes").RemoveAt(Me.BindingContext(dsClientes, "Clientes").Position)End If End Sub |
|
Código para Cancelar a operação | |
Private
Sub
btncancelar_Click(ByVal
sender As System.Object, ByVal e
As System.EventArgs) Handles
btncancelar.Click
Me.BindingContext(dsClientes, "Clientes").CancelCurrentEdit() txtNome.ReadOnly = True txtEndereco.ReadOnly = True txtUF.ReadOnly = True txtNascimento.ReadOnly = True txtTelefone.ReadOnly = True SetButtons(sender, e) End Sub |
|
Código para Salvar as alterações na fonte de dados | |
Private
Sub
btnsalvar_Click(ByVal
sender As System.Object, ByVal e
As System.EventArgs) Handles
btnsalvar.Click
'O método EndCurrentEdit do objeto BindingContext completa o processo de edição Me.BindingContext(dsClientes, "Clientes").EndCurrentEdit()
'Usei o método HasChanges do Dataset para estar certo de que o registro foi modificado antes ' de gastar recursos efetuando um Update na fonte de dados. HasChanges retorna True se ' alguma modificação foi feita. If dsClientes.HasChanges() = True Then'Para escrever as alterações de um registro para o banco de dados você deve chamar o método Update do DataAdapter odaClientes.Update(dsClientes)
'Após editar um registro você precisa preencher o Data Adapter novamenmte. Antes de fazer isto sempre limpe o Data Adapter dsClientes.Clear() 'O método Fill do Data Adapter preenche todos os datasets vinculados a ele odaClientes.Fill(dsClientes, "Clientes") End If txtNome.ReadOnly = True txtEndereco.ReadOnly = True txtUF.ReadOnly = True txtNascimento.ReadOnly = True txtTelefone.ReadOnly = True SetButtons(sender, e) End Sub |
Pronto !! terminamos o projeto. Agora é só testar. Se você testar vai perceber que existem alguns problemas que eu não resolvi neste projeto:
Vamos expandir este projeto incluindo um campo no formulário para exibir a foto do cliente.
Veja a continuação no link : ADO.NET - Salvando e recuperando imagens de um banco de dados
Até a próxima ....
Veja os Destaques e novidades do SUPER DVD VB (sempre atualizado) : clique e confira ! Quer migrar para o VB .NET ? Veja mais sistemas completos para a plataforma .NET no Super DVD .NET , confira... Quer aprender C# ??
Chegou o
Super DVD C# com exclusivo material de
suporte e vídeo aulas com curso básico sobre C# |
Gostou ? Compartilhe no Facebook Compartilhe no Twitter
Referências: