Atualizando DataSets em camadas

Imagine um sistema windows simples, em camadas. Imaginemos uma tabela simples com um campo autonumeração sendo exibida em uma grid. Um componente (pode ser uma classe, componente, etc) devolve um dataSet contendo os dados da tabela e recebe de volta o dataSet para fazer a atualização no servidor.

 

Esse trabalho em camadas gera diversos tipos de problemas, um dos principais é a recuperação do id da autonumeração. Em algumas situações complexas a autonumeração pode chegar a causar um grande desencontro. Que o valor do campo autonumeração inserido no dataSet não baterá com o valor do banco, isso é esperado, mas existe a possibilidade de que o valor gerado pelo banco entre em conflito com algum valor já existente no DataSet, gerando um grande problema.

 

Para evitar que ocorra um conflito tão crítico podemos utilizar as propriedades AutoIncrementSeed e AutoIncrementStep. São propriedades do objeto dataColumn, podemos encontra-las dentro do editor de um dataSet tipado. Atribuindo -1 e -1, respectivamente, faremos com que a autonumeração no dataSet seja negativa. Ao fazer a atualização no servidor o número do servidor será atualizado no dataset, mas não conflitará com nenhum outro número que o dataset já possua.

 

Veja alguns passos no processo de atualização:

 

1) O client precisa enviar os dados a serem atualizados para o servidor. Não deve enviar tudo e sim apenas os dados modificados. Por isso neste momento deve-se utilizar o método getChanges para obter uma cópia do dataset apenas com as mudanças;

 

2) Vamos considerar uma atualização não transacional. Neste caso configuramos a propriedade continueupdateonerror do dataAdapter para true para que ele não devolva erros, apenas marque os registros que gerarem erro de atualização;

 

3) O método de atualização precisa devolver o dataset após a atualização. Isso porque o client está com o dataset inteiro e o client usará o dataset devolvido para saber quais atualizações funcionaram ou não;

 

4) O adapter, ao fazer o método update, tipicamente realiza também um acceptchanges no registro. Porém no caso de inserções isso não pode ser feito por causa da autonumeração. Se fosse feito a mesclagem do dataSet no client falharia, duplicando registros. Então precisamos tratar o evento rowUpdated do adapter para garantir que não seja feito o acceptChanges nos registros inseridos;

 

5) O client pode, após a mesclagem do dataset, fazer um rejectChanges, para imediatamente rejeitar os dados dos registros que falharam na atualização, mas isso é opcional.

 

Veja o exemplo: Eis o client:

 

Dim dados As WindowsControlLibrary1.DS

 

#Region " Windows Form Designer generated code "

 

Public Sub New()

MyBase.New()

 

This call is required by the Windows Form Designer.

 

InitializeComponent()

 

Add any initialization after the InitializeComponent() call

 

End Sub

 

Form overrides dispose to clean up the component list.

 

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

If disposing Then

If Not (components Is Nothing) Then

components.Dispose()

End If

End If

MyBase.Dispose(disposing)

End Sub

 

Required by the Windows Form Designer

 

Private components As System.ComponentModel.IContainer

 

NOTE: The following procedure is required by the Windows Form Designer

It can be modified using the Windows Form Designer.

Do not modify it using the code editor.

 

Friend WithEvents DG As System.Windows.Forms.DataGrid

Friend WithEvents Component11 As WindowsControlLibrary1.Component1

Friend WithEvents Button1 As System.Windows.Forms.Button

 

<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

 

Me.components = New System.ComponentModel.Container

Me.DG = New System.Windows.Forms.DataGrid

Me.Component11 = New WindowsControlLibrary1.Component1(Me.components)

Me.Button1 = New System.Windows.Forms.Button

CType(Me.DG, System.ComponentModel.ISupportInitialize).BeginInit()

Me.SuspendLayout()

DG

Me.DG.DataMember = ""

Me.DG.HeaderForeColor = System.Drawing.SystemColors.ControlText

Me.DG.Location = New System.Drawing.Point(16, 16)

Me.DG.Name = "DG"

Me.DG.Size = New System.Drawing.Size(256, 184)

Me.DG.TabIndex = 0

Button1

Me.Button1.Location = New System.Drawing.Point(104, 224)

Me.Button1.Name = "Button1"

Me.Button1.TabIndex = 1

Me.Button1.Text = "Button1"

Form1

Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)

Me.ClientSize = New System.Drawing.Size(292, 273)

Me.Controls.Add(Me.Button1)

Me.Controls.Add(Me.DG)

Me.Name = "Form1"

Me.Text = "Form1"

CType(Me.DG, System.ComponentModel.ISupportInitialize).EndInit()

Me.ResumeLayout(False)

 

End Sub

 

#End Region

 

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

dados = Component11.ler

DG.DataSource = dados.numeros

End Sub

 

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

If dados.HasChanges Then

Dim d As WindowsControlLibrary1.DS

d = dados.GetChanges

d = Component11.gravar(d)

dados.Merge(d)

dados.RejectChanges()

Else

MsgBox("nada foi mudado")

End If

End Sub

 

Eis o componente :

 

Public Function ler() As DS

DA.Fill(Ds1)

Return (Ds1)

End Function

 

Public Function gravar(ByVal xx As DS) As DS

DA.Update(xx)

Return (xx)

End Function

 

 

Private Sub DA_RowUpdated(ByVal sender As Object, ByVal e As System.Data.OleDb.OleDbRowUpdatedEventArgs) Handles DA.RowUpdated

If e.StatementType = StatementType.Select Then

e.Status = UpdateStatus.SkipCurrentRow

End If

End Sub