Dicas .NET - Atualizando DataSets em camadas

Veja nesta dica, como atualizar DataSets em camadas, nesta dica traremos um exemplo em campos de autonumeração.

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

Confira também

Artigos relacionados