DBHelpers 2, RecordEnumerator

Estou publicando uma nova versão da unit DBHelpers, com algumas novidades interessantes:

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”

  1. Frainer on January 9th, 2008 3:41 pm

    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+

  2. Malta on January 9th, 2008 4:16 pm

    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

Deixe uma Resposta




XHTML: Você pode usar essas tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="">