Copiando estrutura e dados de um DBXReader para ClientDataSet – DataSnap 2010

Aqueles que estão utilizando DataSnap 2010 passam a utilizar o DBXFramework, o qual recomendo muito para operações onde não existe a necessidade de expor e navegação bi-direcional.

Existem casos onde será necessário copiar a estrutura e os dados de um DBXReader para ClientDataSet ou Params, pensando nisso no Delphi foi criada a unit DBXDBReaders.pas que traz algumas classes que permite essa operação.

A classe TDBXDataSetReader possui dois método que permitem copiar para um ClientDataSet já existente ou retorna um novo ClientDataSet, veja o exemplo abaixo.

var
  Reader: TDBXReader;
  DepClient: TDepartmentClient;
begin
  DepClient := TDepartmentClient.Create(DMClientContainer.MyDSServer.DBXConnection, False);

  try
    Reader := DepClient.GetDepartmentsOrderBy;

    try
      if Assigned(Reader) then
      begin
        TDBXDataSetReader.CopyReaderToClientDataSet(Reader, DMClientContainer.CDSCopy);
      end;
    finally
      FreeAndNil(Reader);
    end;

  finally
    DepClient.Free;
  end;

O ClientDataSet CDSCopy já existe e é parte do DataModule DMClientContainer, caso o ClientDataSet não existe, utilizar o método TDBXDataSetReader.ToClientDataSet e esta irá retornar um novo ClientDataSet.

Meus exemplos sobre DataSnap 2010 foram atualizados e você pode efetuar o download aqui.

19 respostas
  1. Rodrigo Carvalho
    Rodrigo Carvalho says:

    Andreano, muito legal estes posts sobre DataSnap. Tenho aprendido bastante com eles e engatinhado na tecnologia, meio aos trancos e barrancos devido a deficiencia de material para estudo (principalmente em português) mas tá indo.rsrs… Tenho uma dúvida que gostaria de compartilhar aki no seu blog. Quando uso o método toClientDataSet ele trunca os campos do Reader, você sabe como posso resolver isso? Ex: Tenho um campo no Reader com 150 caracteres, no reader legal tenho os 150 depois q converto, nos novos campos do clientdataset ele armazena apenas os 20 primeiros caracteres. Já observei que 20 é o número padrão quando criamos um datasetfiels do tipo string… tem algo haver?
    Grande abraço.

    Responder
    • Andreano Lanusse
      Andreano Lanusse says:

      Oi Rodrigo,

      obrigado por visitar o blog e bom saber que estas aprendendo, estamos cada vez mais trazendo materiais em português.

      Sobre o seu problema, o seu ClientDataSet já tinha os TFields pré definidos? Se você está criando os TFields antes não precisaria, pois o método faz isso pra você.

      Responder
  2. Andreano Lanusse
    Andreano Lanusse says:

    Oi Marcos,

    Vai na unit DBXDBReaders na procedure CopyValueTypeProperties, localize a linha onde está
    if ValueType.DataType = TDBXDataTypes.WideStringType then

    e mude para

    if ValueType.DataType in [TDBXDataTypes.WideStringType, TDBXDataTypes.AnsiStringType] then

    Isso irá resolver o problema de truncar.

    Responder
  3. Rodrigo
    Rodrigo says:

    Olá Andreano, estou com uma dúvida, é a seguinte:

    tenho a consulta “SELECT * FROM TABELA WHERE ID=:pID”

    como passar pelo dbexpress vários valores para a coluna ID?

    visto que se eu utilizar, ClientDataSet1.Params[0].AsInteger := 1 só poderei trazer o registro cujo valor da coluna ID é 1,

    Gostaria de trazer vários registros cujo valor da coluna ID seria 1,2,3,4,60,90,80,56

    Responder
  4. Carlos Gonzaga
    Carlos Gonzaga says:

    Andreano !
    Seguindo a dica q vc passou p/ o Marcos. Como eu posto as alterações p/ uam nova unit DBXDBReaders.dcu ja q faz parte da lib da VCL?

    Responder
  5. Rodrigo Martim
    Rodrigo Martim says:

    Boa tarde Andreano,

    Fiz o ajuste no arquivo DBXDBReaders.pas, incluindo o conteudo postado por você ao Marcos, porem continuo com o problema.

    1º Pergunta: Existe alguma forma de depurar esta Unit? Gostaria de entender o que está acontecendo.

    2º Pergunta: Há necessidade de alguma compilação apos alterar o DBXDBReaders.pas ou só salvar e compilar o projeto?

    Embarcadero® Delphi® XE Version 15.0.3953.35171

    Agradecido desde já pela sua ajuda,
    Atenciosamente,
    Rodrigo Martim.

    Responder
  6. Rodrigo Martim
    Rodrigo Martim says:

    OBS: A solução partiu 100% do Sr Andreano. estou postando por que notei que ele não postou este complemento.

    Problema resolvido:

    Apenas para complementar e ajudar pessoas que venham a ter a mesma duvida.

    Tem que compilar o .pas e jogar a dcu gerada pelo mesmo na pasta lib\debug e lib\release dentro das pasta do delphi, apos isso a correção irá funcionar.

    Mais uma vez obrigado pela dica Andreano.
    Sucesso!

    Responder
  7. Carlos Gonzaga
    Carlos Gonzaga says:

    Resolvi o problema com os campos definidos em run-time.
    Veja a rotina que define 2 (dois) campos do tipo string de tamanho variado no ClientDataSet (cdsBusca) .
    Isso responde tbm a pergunta do Carvalho, pois internamente o padrão para campos string é 20
    procedure TfrmBusca.DoDefColumns;
    var f:TFieldDef ;
    begin
    cdsBusca.FieldDefs.Clear ;

    f.Name :=’NOME’;
    f.DataType :=ftString ;
    f.Size :=50 ;

    f.Name :=’EMAIL’;
    f.DataType :=ftString ;
    f.Size :=80 ;

    cdsBusca.CreateDataSet ;
    end;

    Responder
  8. Wendel Wagner
    Wendel Wagner says:

    if Assigned(Reader) then
    begin
    Try
    //Tentando com a Opção Normal, se der erro copiamos um a um
    TDBXDataSetReader.CopyReaderToClientDataSet(Reader, pCds);
    except
    while Reader.Next do
    begin

    pCDS.Append;

    //Preenchendo a tabela
    for I := 0 to Reader.ColumnCount – 1 do
    begin
    //Pega o nome do campo
    VCampo := Copy( Reader. Query.Fields[I].FieldName,1,32);

    for y := 0 to pCds.FieldCount – 1 do
    begin
    VNome_Campo := Copy(pCds.Fields[y].FieldName,1,32);

    if VNome_Campo = VCampo then
    pCds.Fields[y].Value := Query.Fields[I].Value;
    end;
    end;

    pCds.FieldByName(‘SEL_GRID’).Value := ‘N’;

    pCDS.Post;

    Query.Next;
    end;
    End;
    end;

    Com a opção CopytoCds qdo tem coluna Blob da erro de “!FEATURE NOT IMPLEMENTED”..Estou tentando copiar coluna por coluna..mas ainda nao deu certo..existe outra forma de fazer isso?

    Responder
  9. Claudio
    Claudio says:

    Andreano, Boa Tarde.

    Estou utilizando TDBXReader para navegadar dados do servidor para o cliente.
    O problemas é o seguinte:

    Tenho um metodo no Servidor chamdo GetListaDeClientes e no cliente executo o seguinte comando
    vReader := proxyCliente.GetListaDeClientes;

    Quando executo esse comando FreeAndNil(vReader) e FreeAndNil(proxyCliente) o sistema da um erro ‘Invalid Pointer’, mas segui exatamento o exemplo que foi postado.
    O que pode ser?
    Estou utilizando Delphi2010.

    Responder
  10. Rafael Pasa
    Rafael Pasa says:

    Boa tarde Andreano!!!

    Preciso copiar um DBXreader para um objeto. Tenho uma classe que converte um clientDataSet para um objeto, segue o código abaixo:

    class procedure TMsysClassUtils.CarregarDoClientDataSet(const _AFields: TFields; _AObj: TObject);
    var
    PropList: PPropList;
    PropListCount: byte;
    I: integer;
    begin
    PropListCount := GetPropList(_AObj, PropList);
    for I := 0 to pred(PropListCount) do
    begin
    if not _AFields.FieldByName(string(PropList[I].Name)).IsNull then
    SetPropValue(_AObj, string(PropList[I].Name), _AFields.FieldByName(string(PropList[I].Name)).AsVariant);
    end;
    end;

    Então pensei em converter o DBXREader para um ClienteDataSet e depois para o objeto. mas ae tive um problema, no Reader vem um campo Observações(Tipo Blob).E a função CopyReaderToClientDataSet dispara um exceção NotImplemeted.
    Tem aguma forma de adaptar essa minha função para manipular um DBXREaders e suportar Blob, ou alguma outra solução para meu problema

    Responder
  11. Júlio César Ferreira (@jcmferreira)
    Júlio César Ferreira (@jcmferreira) says:

    Grande Andreano…

    Estou tentando adaptar o sistema da empresa para a tecnologia DataSnap, que é extremamente incrível.

    Em nosso caso, nossas queries no lado do servidor, são realizadas através dos componentes ADODB.

    Minha pergunta: É possível realizar um TDBXDataSetReader.Create a partir de um TADOQuery e disponibilizar o TDBXReader criado para as aplicações clientes?

    Responder

Trackbacks & Pingbacks

Deixe uma resposta

Want to join the discussion?
Feel free to contribute!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *


This site uses Akismet to reduce spam. Learn how your comment data is processed.