VB.NET - Acessando linhas deletadas em um DataTable


Você sabia que quando deleta linhas de um DataSet na verdade elas são marcadas para deleção até que as mudanças seja confirmadas pela chamada direta o indireta do método AcceptChanges() ?

Sabia também que pode ter acesso a estas linhas antes de sua deleção ?

Pois é , vivendo e aprendendo. Neste artigo vou mostrar como você pode acessar linhas deletadas em um objeto DataTable.

Na verdade fazer isto é muito simples:

  1. Você pode usar um objeto DataView ou

  2. Você pode usar o método Select() do objeto DataTable

para ter acesso às linhas deletadas.

Cenário:

1- Vamos criar um projeto que acessa a tabela Orders do banco de dados Northwind.mdb exibindo todos os registros em um objeto DataGrid usando uma instrução SQL Select do tipo : Select * From Orders.

2- Usaremos dois radiobutton e um caixa de Texto : um para exibir os registros deletados e outro para exibir os registros atuais. Os registros serão exibidos na caixa de texto.(para isto sua propriedade Multiline deve ser definida como True)

3- A princípio os registros serão exibidos e não haverá nenhum registro deletado. Para deletar selecione uma linha ou mais do datagrid e pressione a tecla DEL.

4- Após fazer isto basta clicar no radiobutton - rdbLinhasDeletadas para que os registros que você deletou sejam mostrados.

O Projeto

Inicie um novo projeto no VS.NET do tipo Windows Application usando a linguagem VB.NET e no formulário padrão - form1.vb- inclua os seguintes componentes:

Componente Nome
1 DataGrid DataGrid1
2 radiobutton rdbLinhasAtuais de rdbLinhasDeletadas
1 TextBox txtLinhasDeletadas (Multiline=True)

Abaixo o jeitão do projeto:

Para  utilizar o StringBuilder e o acesso a um banco de dados Access usando  o provedor OleDb. vamos precisar dos seguintes imports:

A

Imports System

Imports System.Configuration

Imports System.Text

Imports System.Data.OleDb

 

Precisamos também definir o objeto DataView - dv, no inicio do formulário,  assim :

Private dv As DataView

Inclua um arquivo de configuração conforme mostrado em no artigo  .NET - Tratando arquivos de configuração . O arquivo conterá a string de conexão com o banco de dados Northwind.mdb .

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<appSettings>

<add key="acessoBD" value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\teste\Northwind.mdb" />

</appSettings>

</configuration>

Agora vamos ao código do projeto:

NO evento Load do formulário inclua o código :

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


' preenche a tabela de pedidos

Dim da As New OleDbDataAdapter("SELECT * FROM Orders", ConfigurationSettings.AppSettings("acessoBD"))


'define um novo DataTable baseado na tabela Orders

Dim dt As New DataTable("Orders")


'preenche o datadapter

da.Fill(dt)


' define uma visão das linhas atuais

dv = New DataView(dt, Nothing, Nothing, DataViewRowState.CurrentRows)


'atribui o dataview ao objeto datagrid

DataGrid1.DataSource = dv


'marca o radiobutton

rdbLinhasAtuais.Checked = True


End
Sub

No evento checkedChanged do radiobutton - rdbLinhasAtuais - que exibe as linhas atuais inclua o código:

Private Sub rdbLinhasAtuais_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles
rdbLinhasAtuais.CheckedChanged


' efetua um filtro para exibiri somente linhas atuais

dv.RowStateFilter = DataViewRowState.CurrentRows


'define o datagrid de modo a permitir a deleção

DataGrid1.ReadOnly = False


'limpa a caixa de texto

txtLinhasDeletadas.Clear()

End Sub

No evento checkedChanged do radiobutton - rdbLinhasDeletadas - que exibe as linhas deletadas inclua o código:

Private Sub rdbLinhasDeletadas_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rdbLinhasDeletadas.CheckedChanged

 

' filtra o view para incluir somente linhas deletadas

dv.RowStateFilter = DataViewRowState.Deleted

 

'define o datagrid como somente leitura (não permite deleção)

DataGrid1.ReadOnly = True

' obtem o DataTable a partir do DataView

Dim dt As DataTable = dv.Table

 

' faz o filtro usando DataTable RowState

Dim delRows As DataRow() = dt.Select(Nothing, Nothing, DataViewRowState.Deleted)

 

'define um stringbuilder para

Dim sb As New StringBuilder("Registros deletados:" & Environment.NewLine)

 

'define um objeto row para

Dim row As DataRow

 

' percorre a coleção de linhas deletadas(deleted rows)

For Each row In delRows

    sb.Append(("Pedido : " & row("OrderID", DataRowVersion.Original) & Environment.NewLine))

Next row

 

'exibe no textbox a relação de linhas deletadas

txtLinhasDeletadas.Text = sb.ToString()

End Sub

Para saber mais sobre o StringBuilder leia o artigo: VB .NET - StringBuilder : tratando Strings de modo mais eficiente.

Executando o projeto teremos:

Selecionando as linhas para Deleção e Teclando DEL em seguida

Exibindo as linhas deletadas

Um pouco de teoria sobre o assunto:

ADO.NET gerencia o estado das linhas enquanto elas estão sendo modificadas. Abaixo temos os estados atribuídos as linhas pela enumeração DataRowState.

Valor

Descrição

Added

A linha foi incluida na coleção de linhas na tabela mas o método  AcceptChanges( ) não foi chamado ainda.

Deleted

A linha foi deletada da coleção de linhas na tabela mas o método  AcceptChanges( ) não foi chamado ainda.

Detached

A linha não pertence a coleção de linhas no  DataTable.

Modified

Os dados na linha foram alterados mas o método AcceptChanges( ) não foi chamado

Unchanged

Os dados na linha não foram alterados desde que ela foi carregada ou desde que o método AcceptChanges( foi chamado

Quando o método AcceptChanges é chamado no DataSet, o DataTable ou o DataRow quer de forma explícita quer de forma implícita via método update() do objeto DataAdpater, ocorre o seguinte:

Quando o método RejectChanges é chamado no DataSet , DataTable ou DataRow ocorre o seguinte:

Cada DataRow tem uma propriedade chamada RowState que retorna o estado atual da linha.

ADO.NET mantém diversas versões dos dados em cada linha enquanto ela esta sendo modificada para permitir a reconciliação do modo desconectado com a fonte de dados. Abaixo temos a tabela que mostra os valores para a enumeração DataRowVersion.

Valor

Descrição

Current

O valor atual. Esta versão não existe para linhas com o estado Deleted.

Default

Valor padrão como determinado pelo DataRowState:

  • A versão atual para linhas com valores de estado igual a :Added, Modified ou Unchanged.

  • A versão original para linhas com estado Deleted.

  • O valor proposto para linhas com valor Detached

Original

O valor Original . Esta versão não existe para linhas com estado Added.

Proposed

Valor proposto.Este valor existe durante a edição da linha quer implicitamente ou explicitamente com o método BeginEdit( ) e para linhas com estado Detached.

O método HasVersion( ) do objeto DataRow verifica se uma versão particular da linha existe.

A enumeração (enumeration) DataViewState é usada para retornar uma versão particular dos dados ou para determinar se a versão existe, Os métodos Select() do objeto DataTable e a propriedade RowStateFilter do DataView usam o DataViewState com este propósito. Você pode retornar mais de uma versão usando um valor booleano OR de valores DataViewRowState. A tabela abaixo mostra os valores para DataViewRowState:

Valor

Descrição

Added

A versão atual de todas as linhas incluidas.

CurrentRows

A versão atual de todas as linhas inalteradas, incluidas e modificadas. Valor padrão

Deleted

A versão original de todas as linhas deletadas

ModifiedCurrent

A versão atual de todas as linhas modificadas.

ModifiedOriginal

A versão original de todas as linhas modificadas.

None

Sem linhas

OriginalRows

A versão original das linhas não alteradas, modificadas e deletadas.

Unchanged

A versão atual de todas as linhas inalteradas.

A versão atual de cada linha é retornada por padrão quando elas são acessadas no DataTable ou no DataView. A solução usada obtêm linhas deletadas de um DataTable  e de um DataView. As linhas deletadas incluem somente aquelas marcadas para deleção usando o método Delete() do DataRow() ou do DataView, mas não o método Remove() ou RemoveAt() de DataRowCollection, que removem imediatamente a linha da coleção DataRow().

A solução apresentada usa duas técnicas:

1- Para obter as linhas deletadas do DataTable usamos um método Select() sobrecarregado do DataTable para retornar um vetor de objetos DataRow.  O método aceita um argumento que tem um valor da enumeração DataViewRowState. Para retornar as linhas deletadas passamos o valor Deleted como argumento.

2- Para obter as linhas deletadas de um DataView definimos a propriedade  RowStateFilter como Deleted. As linhas deletadas também são visíveis junto com as demais linhas se definirmos a propriedade RowStateFilter como ModifiedOriginal e OriginalRows.

Aguarde mais artigos sobre VB.NET.


José Carlos Macoratti