• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Ridelight

UnderlyingValues e OriginalValues

1 mensagem neste tópico

Os objetos Field de ADO possuem as propriedades UnderlyingValue o OriginalValue.

Com elas é possível saber qual o valor anterior de um campo a meio a uma operação de edição, qual o valor originalmente obtido da base de dados para o campo e mesmo armazenar informações para tratar colisão de dados que ocorram no momento da actualização da base de dados. Ter estes valores nas propriedades de um objecto de acesso a dados pode enriquecer as possibilidades de manipular o ocbjeto e não custa muito em termos de código, porque a maior parte do código é repetitiva e basta copiar e colar.

Para implementar estas propriedades, podem criar uma variável do tipo matriz de variantes no módulo da classe. Esta matriz terá tantas linhas quantas sejam as propriedades para as quais querem implementar estes recursos. As colunas serão em número de três. Na primeira coluna estarão os elementos que contêm os valores actuais das propriedades, na segunda coluna ficarão os valores correspondentes aos UnderlyingValues e na terceira coluna os valores correspondentes aos OriginalValues. Chamem a esta matriz de Propriedades. Supondo que têm um objecto Cliente com cinco propriedades. A matriz Propriedades será definida assim:

Private Propriedades( 1 To 5, 1 To 3) As Variant

Para facilitar o acesso aos elementos da matriz Propriedades criamos duas enumerações públicas: uma que usaremos para referenciar as colunas e outra para referenciar as linhas da matriz Propriedades. A enumeração para referenciar as colunas pode ser uma só para todos os objectos em que usarmos este esquema. Veja abaixo:

Public Enum PROP_VALUES

         CURRENT_VALUE = 1 ' valor actual da propriedade

        UNDERLYING_VALUE = 2  ' valor anterior à edição que está em curso

        ORIGINAL_VALUE = 3  'valor inicialmente obtido da base de dados

End Enum

Para referenciar as linhas da matriz teremos que ter em cada objecto uma enumeração própria. No caso do objecto Cliente suposto acima, poderíamos ter uma enumeração em que cada valor corresponde a uma propriedade e à linha de Propriedades em que serão armazenados os valores da propriedade.

Public Enum PROP_CLIENTE

       CLI_ID = 1

        CLI_NOME = 2

       CLI_CPF = 3

       CLI_ENDERECO = 4

       CLI_FONE = 5

End Enum

Para exemplificar o uso disto, ao definirmos os procedimentos da propriedade "Nome" faríamos como abaixo:

Public Property Get Nome () As String

    Nome = Cstr(Properties(CLI_NOME, CURRENT_VALUE))

End Property

Public Property Let Nome ( NewValue As String )

    Properties(CLI_NOME, CURRENT_VALUE) = NewValue

End Property

Para acedermos aos valores de UnderlyingValue e OriginalValue teríamos rotinas genéricas válidas para todas as propriedades e que são sempre as mesmas em qualquer objecto, mas mudando apenas o tipo de enumeração usada no argumento.

Public Property Get OriginalValue(prop As PROP_CLIENTE) As Variant

    OriginalValue = Properties(prop, ORIGINAL_VALUE)

End Property


Public Property Get UnderlyingValue(prop As PROP_CLIENTE) As Variant

    UnderlyingValue = Properties(prop, UNDERLYING_VALUE)

End Property

Vejamos então como tirar proveito destas informações adicionais que podem agora armazenar sobre suas propriedades.

Supondo que estamos expondo um objecto Cliente em uma janela de edição. O utilizador vai alterando os valores dos campos de dados e vamos transferindo estes valores para as propriedades do objecto Cliente subjacente. Ao clicar em OK,  o utilizador está sinalizando que quer tornar as modificações definitivas. Mas se der um clique em Cancelar ou fechar a janela sem concluir a operação de edição, podem restaurar as propriedades do objecto ao que eram antes de se iniciar a edição. Faz-se isto procurando os valores das propriedades nos seus  UnderlyingValues. No caso de o utilizador confirmar as alterações, podemos guardar os valores actuais também nos UnderlyingValues de cada propriedade e comandar ao Objecto que se guarda na base de dados.  Veja abaixo uma rotina que actualizaria os UnderlyingValues com os valores actuais de cada propriedade:

Private Sub UpdateUnderlyingValues()

    Dim i As Long

    For i = 1 To UBound(Properties, 1)
        Properties(i, UNDERLYING_VALUE) = Properties(i, CURRENT_VALUE)
    Next i

End Sub

No caso do utilizador cancelar a edição clicando em Cancelar, a rotina abaixo poderia ser usada para restaurar os valores das propriedades:

Public Sub CancelEditing()      
      Dim i As Long

     For i = 1 To UBound(Properties, 1)

         Properties(i, CURRENT_VALUE) = Properties(i, UNDERLYING_VALUE)

     Next i 

End Sub

Se o ocbjeto encontrar um conflito de dados durante a actualização da base de dados, podemos pesquisar as propriedades actuais do objecto na base de dados e armazenar estes valores nos UnderlyingValues de cada propriedade. Ao retornar um erro de conflito ou colisão de dados, uma rotina de tratamento de erros dentro do objecto poderá usar os UnderlyingValues e OriginalValues para tratar o erro. Ao comparar cada valor de UnderlyingValue com o seu correspondente OriginalValue, será possível descobrir quais valores foram alterados por outro utilizador desde que o registro foi inicialmente lido. Com estas informações é possível informar o utilizador actual do que ocorreu e pedir-lhe uma tomada de decisão sobre o que fazer. Caso o utilizador queira sobre-gravar as informações atuais com as suas, mesmo sendo as mais atigas, você pode igualar as propriedades OriginalValues às retornadas do banco de dados em UnderlyingValues para evitar novos conflitos e actualizar mesmo assim. Se quiser preservar as actualizações do outro utilizador, iguale os valores das propriedades onde ocorreu conflito com os que estão em UnderlyingValues . Feito isto, comande novamente a gravação do objecto. Veja abaixo uma rotina que pode ser usada para sincronizar o estado actual do objecto com as informações colhidas da base de dados após uma constatação de conflito. O argumento Keep é usado para sinalizar se o que se quer é a sobre-gravação total dos dados no BD ou se as alterações feitas por outros devem ser preservadas.

Private Sub AdjustToResyncData(ByVal keep As Boolean)

    Dim i As Long

    For i = 1 To UBound(Properties)
         If Properties(i, CURRENT_VALUE) <> _
              Properties(i, UNDERLYING_VALUE) Then ' houve conflito de dados
              If keep Then 'mantém alterações de outros usuários
                     Properties(i, ORIGINAL_VALUE) = Properties(i, UNDERLYING_VALUE)
                     Properties(i, CURRENT_VALUE) = Properties(i, UNDERLYING_VALUE)
              Else ' sobregrava
                     Properties(i, ORIGINAL_VALUE) = Properties(i, UNDERLYING_VALUE)
                     Properties(i, UNDERLYING_VALUE) = Properties(i, CURRENT_VALUE)
              End If
         End If
    Next i

End Sub 

Acrescente-se ao que foi visto acima que podem também criar uma propriedade DataChanged para sinalizar quando o objeto foi modificado em relação ao seu estado original. Veja abaixo como:

Public Property Get DataChanged() As Boolean
    Dim i As Long

    DataChanged = False
    For i = 1 To UBound(Properties)
        If Properties(i, CURRENT_VALUE) <> Properties(i, ORIGINAL_VALUE) Then
            DataChanged = True
            Exit Property
        End If
    Next i

End Property

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora