DBHelpers 2, RecordEnumerator
Estou publicando uma nova versão da unit DBHelpers, com algumas novidades interessantes:
- Nova propriedade Editing em TDataSetHelper, equivalente a
State in dsEditModes
- Novo método Sum em TDataSetHelper, que retorna o somatório dos valores de um campo numérico, opcionalmente considerando um filtro
- Nova propriedade CurrentIsNull em TFieldHelper (sugestão de Bruno Sanson)
- RecordEnumerators: classe, interface e método GetEnumerator de TDataSetHelper, que facilita a rotina de percorrer os registros de um dataset.
- Algumas mudanças na sintaxe de ForEach
Não cheguei a comentar antes sobre o método ForEach, que já estava disponível desde a primeira versão. ForEach recebe como parâmetro o ponteiro de uma função callback que é chamada para cada registro do dataset. Você pode ver um exemplo na implementação do novo método Sum. Uma alternativa é usar o novo RecordEnumerator.
RecordEnumerator
A idéia é fazer um loop percorrendo os registros de um dataset tomando os cuidados de desabilitar os controles visuais (DisableControls), salvar os valores correntes das propriedades Active, Filter, Filtered e Bookmark do dataset e no fim do loop restaurar automaticamente o dataset ao seu estado original.
Por exemplo, veja o código abaixo:
var ARecord: IRecordEnumerator; begin ARecord := TRecordEnumerator.Create(cdsPedidos, 'total > 1000'); while ARecord.MoveNext do { Faz alguma coisa em cdsPedidos } end; end;
O que faz é percorrer um dataset cdsPedidos filtrado por ‘total > 1000′ do início ao fim, sendo que ao final o dataset é restaurado ao seu estado original. Sem usar IRecordEnumerator, o mesmo código seria escrito como:
var AFilter: String; OldActive: Boolean; OldFilter: String; OldFiltered: Boolean; Position: TBookmarkStr; begin AFilter := 'total > 1000'; Position := cdsPedidos.Bookmark; cdsPedidos.DisableControls; try OldActive := cdsPedidos.Active; OldFilter := cdsPedidos.Filter; OldFiltered := cdsPedidos.Filtered; cdsPedidos.Active := True; if AFilter <> '' then begin cdsPedidos.Filter := AFilter; cdsPedidos.Filtered := True; end; try cdsPedidos.First; while (not cdsPedidos.EOF) do begin { Faz alguma coisa com cdsPedidos } cdsPedidos.Next; end; finally if AFilter <> '' then begin cdsPedidos.Filter := OldFilter; cdsPedidos.Filtered := OldFiltered; end; end; finally cdsPedidos.Bookmark := Position; cdsPedidos.EnableControls; cdsPedidos.Active := True; end; end;
A classe TRecordEnumerator suporta interfaces, portanto você não precisa se preocupar em desalocar a instância. Apenas atribua uma instância da classe a uma variável IRecordEnumerator e quando sair do escopo, o compilador vai automaticamente liberar a instância, chamando o destructor que restaura o status do dataset.
Se precisar restaurar o dataset antes do fim da rotina, tudo o que precisa fazer é liberar manualmente o objeto RecordEnumerator usando uma classe no lugar de uma interface e chamando o método Free ou usando uma interface e atribuindo nil à variável.
O método GetEnumerator de TDataSetHelper retorna uma interface para um novo TRecordEnumerator:
function GetEnumerator(const Filter: String = ''): IRecordEnumerator;
Download
Faça aqui o download da última versão de DBHelpers.
Update
17/01/08 Corrigidos bugs de TRecordEnumerator na versão 3.
Comments
2 Responses to “DBHelpers 2, RecordEnumerator”
Deixe uma Resposta

Daniel,
Parabéns pela criativa.
Agora tenho uma dúvida.
Sua classe não funciona em delphi 7?
Existe alguma alternativa para utilizar esse recurso em Delphi 7?
Flw, t+
Frainer,
Class helpers só foram introduzidas no Delphi 8, portanto a unit DBHelpers não funciona em Delphi 7. Por outro lado, o código da classe TRecordEnumerator e da interface IRecordEnumerator é totalmente suportado por versões anteriores da linguagem.
Vamos fazer o seguinte, vou adicionar diretivas de compilação na unit para desabilitar o código de class helpers para versões anteriores e manter o RecordEnumerator livre. Daí você (e outros usuários de D7, D6, D5…) poderão continuar usando a unit original, com eventuais melhorias.
Acho que nem preciso dizer que o código é open-source e não tem nenhuma garantia implícita, né? Bem, se precisava eu agora já disse.
:)
Um abraço!
Malta