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:
- 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;
- 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;
- 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;
- 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;
- 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.
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
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