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.
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.
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ê.
Também estou com este problema alguém tem a solução?
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.
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
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?
Carlos,
Se você está usando a versão comprada do Delphi, você tem os fontes da VCL. O trial não traz os fontes da VCL.
Felismente so temos a liçença do Delphi 2007! Estou avaliando o delphi 2010 p/ adota-lo, mas estou encontrando estes probleminhas.
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.
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!
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;
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?
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.
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
@Wender, o suporte a Blob foi implementado no Delphi XE2 Update 2, leia esse artigo http://www.andreanolanusse.com/pt/copyreadertoclientdataset-blob-e-a-mensagem-feature-not-implemented/
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?