[primeira parte]

2. Preparando o Sensor

Escolha o seu sensor entre os vários disponíveis em MySensors – baixe o código e siga as recomendações – pode acreditar… vai funcionar.

Os programas escritos para Arduino seguem o padrão C/C++ (ver mais) e utilizam uma IDE básica com suporte a uma variedade impressionante de processadores da linha ATMEL.

Uma vez instalado a IDE e feito escolha do sensor que irá utilizar o próximo passo será montar a parte eletrônica do sensor ( Arduino + Rádio + Sensor ).sensors

Agora que já tem o código do sensor e a eletrônica montada – é hora de transferir o programa para o arduino – vai encontrar farto material de como fazer isto tanto em MySersors como em  arduino.cc.

Se tudo deu certo… você já tem um sensor funcionando…

 

Até aqui não temos Delphi… na próxima fase vamos trabalhar o Gateway.

 

[continua]

 

Uma solução popular para integração de IoT é fazer uso da plataforma Arduino como base de aquisição de dados de campo.

Para alguém que nasceu enfiado no código, como eu, a eletrônica parece se uma barreira – esquece… isto era antes de Arduino.

“Arduino, palavra por vezes traduzida ao português como Arduíno, é uma plataforma de prototipagem eletrônica de hardware livre e de placa única, projetada com um microcontrolador Atmel AVR com suporte de entrada/saída embutido, uma linguagem de programação padrão, a qual tem origem em Wiring, e é essencialmente C/C++. O objetivo do projeto é criar ferramentas que são acessíveis, com baixo custo, flexíveis e fáceis de se usar por artistas e amadores. Principalmente para aqueles que não teriam alcance aos controladores mais sofisticados e de ferramentas mais complicadas.” (Wikipédia)

Como plataforma de prototipagem permite infinitas possibilidades de soluções e conexões com sensores e interação com objetos nas mais diversas área da tecnologia. Arduino como precursora dos processadores que cabem na palma da mão – praticamente se tornou um padrão de mercado para a indústria, onde já encontramos importantes players se dedicando em lançar produtos/placas com a filosofia disseminada pelo Arduino.

Quando se olha do lado do hardware, encontramos em MySensors uma base de integração bem servida de sensores e atuadores para soluções comuns do dia-a-dia.

Como protocolo MySensors estabelece regras simples de troca de informações por porta SERIAL ou TCP/IP (Ethernet) no PC e Rádio (sem fio) no lado do hardware, que permite receber dados coletados de campos e/ou enviar dados para os sensores de campo utilizando comunicação sem fio (rádio).

Quando um ponto MySensors se comunicam sem si ( entre sensores ), ele utiliza uma estrutura de rede MESH em que estabelece uma relação de recepção dos dados endereçados ao próprio ponto (sensor) e retransmissão do sinal quando
forem informações destinados a outro sensor seu vizinho. De forma colaborativa em uma rede MESH o dado viaja entre os sensores até chegar ao seu mestre principal (gateway-gw) – o que torna cada ponto (sensor) em um repetidor (R) de sinal;

Um sensor envia um dado para o Gateway em formato texto (ex: 12;6;0;0;3;My Light\n) – se o destino/Gateway estiver fora do alcance, o dado é retransmitido pelos vizinhos até chegar ao seu destino final.

Uma variedade de sensores podem ser conectados ao seu Arduino que se comunica com o Gateway usando protocolo MySensors e chega ao PC para gerência, armazenamento e/ou reação comandando novas ordens aos sensores.

[continua…]

Quando se trata de eventos o mais comum é encontrar uma propriedade que recebe um ponteiro para um procedimento.

Um tipo de evento comum é

property OnClick:TNotifyEvent ….

Para atribuir o evento ao objeto é preciso construir um procedimento para a classe e associá-lo ao evento do objeto, se você já tentou atribuir um procedimento que não esta ligado a uma classe, já notou que há limitações.

Porque criar um novo procedimento em uma classe que será utilizado em um objeto específico… Com eventos anônimos não precisa. (fontes)

[code lang=”pascal”]
TMinhaClasse = class(TObjectExt)
end;
…..

var FObjMinhaClasse:TMinhaClass;
begin
// definindo o evento anônimo
FObjMinhaClasse:= TMinhaClasse.create;
FObjMinhaClasse.onFireEvent := procedure (sender:TObject)
begin
……
end;
end;

// usando o evento anônimo
FObjMinhaClasse.FireEvent(sender);

[/code]

 

Recriando TObject

[code lang=”pascal”]

TObject = class(System.TObject)
private
FOnFireEvent: TProc<TObject>;
procedure SetOnFireEvent(const Value: TProc<TObject>);
public
procedure FireEvent;overload;
procedure FireEvent(Sender:TObject);overload;
property OnFireEvent:TProc<TObject> read FOnFireEvent write SetOnFireEvent;
end;

…..
{ TObject }

procedure TObject.FireEvent;
begin
FireEvent(self);
end;

procedure TObject.FireEvent(Sender: TObject);
begin
if assigned(FOnFireEvent) then
FonFireEvent(Sender);
end;

procedure TObject.SetOnFireEvent(const Value: TProc<TObject>);
begin
FOnFireEvent := Value;
end;
[/code]

 

Exemplos

Este post foi inspirado no livro do Nick Hodges “Coding in Delphi”

 

Estava trabalhando para simplificar o TRESTClient do DataSnap  e implementar alguns recursos que gostaria de ter e não encontrei no componente distribuido com o delphi ( Package para TRESTSocialClient ). Mapear as respostas Array para um TFDDataset primordial para facilitar o desenvolvimento (ex: TRESTSocialClientDataset). E quando não é possível mapear para um Dataset… código+código+bug+complexo…

Quando trabalho com um Servidor REST Datasnap escrito para delphi – a integração é simples utilizando o “Wizard” para criar um projeto REST Client disponível. Quando o servidor REST responde para múltiplas plataformas é imperativo que o servidor envie respostas “padronizadas” que sejam compatíveis com a plataforma que o cliente utiliza. O caminho mais rápido é responder JSON padrão evitando respostas específicas de uma plataforma ou outra.

Exemplo: um método não pode responder com um TDataset.Data como é o indicado pelo Delphi… isto obrigaria que o cliente seja igualmente um Delphi.. Então para manter padrão o método deve responder com um TJSONValue ou TJSONObject.

Tomando por base o Servidor Datasnap do post “FireDAC – Datasnap” onde publica o método  GetCliente/{cnpj} (http://localhost:8080/datasnap/rest/TServerMethods1/GetCliente/123456) que retorna:

[code lang=”JSON”]
{"result":[{"cliente":[{"RowId":1,"codigo":1,"nome":"Embarcadero SA","cidade":"Sao Paulo","estado":"SP","endereco":"Rua…xxxx…,10","debitos":100000.12},{"RowId":2,"codigo":2,"nome":"Embarcadero SA2","cidade":"Sao Paulo","estado":"SP","endereco":"Rua…xxxx…,10","debitos":100000.12}],"adicional":[{"codigo":1,"nome":"Exemplo 2"}]}]}
[/code]

Nas andanças pelos BLOGs de MVPs encontrei um projeto “Introducing JsonToDelphiClass” que aponta para o repositório com o código do projeto.

O projeto JsonToDelphiClass permite que a representação JSON de retorno do servidor DataSnap seja colado no espaço para texto indicada e usar o botão de geração da Unit contendo a classe Delphi para a representação JSON.

As classes geradas pelo projeto possuem um método que fornecendo o código de retorno do servidor – popula o objeto delphi – facilitando a conversão da estrutura JSON para Classe.

class function FromJsonString(AJsonString: string): T... (criar a classe e popula)

.

Passando aquele retorno do Servidor, veja como ele construiu as classes para a representação JSON:

[code lang=”pascal”]
unit JsonRestServer;

// *************************************************
// Generated By: JsonToDelphiClass – 0.65
// Project link: https://github.com/PKGeorgiev/Delphi-JsonToDelphiClass
// Generated On: 2016-04-10 15:41:06
// *************************************************
// Created By : Petar Georgiev – 2014
// WebSite : http://pgeorgiev.com
// *************************************************

interface

uses Generics.Collections, Rest.Json;

type

TAdicionalClass = class
private
FCodigo: Extended;
FNome: String;
public
property codigo: Extended read FCodigo write FCodigo;
property nome: String read FNome write FNome;
function ToJsonString: string;
class function FromJsonString(AJsonString: string): TAdicionalClass;
end;

TClienteClass = class
private
FRowId: Extended;
FCidade: String;
FCodigo: Extended;
FDebitos: Extended;
FEndereco: String;
FEstado: String;
FNome: String;
public
property RowId: Extended read FRowId write FRowId;
property cidade: String read FCidade write FCidade;
property codigo: Extended read FCodigo write FCodigo;
property debitos: Extended read FDebitos write FDebitos;
property endereco: String read FEndereco write FEndereco;
property estado: String read FEstado write FEstado;
property nome: String read FNome write FNome;
function ToJsonString: string;
class function FromJsonString(AJsonString: string): TClienteClass;
end;

TResultClass = class
private
FAdicional: TArray<TAdicionalClass>;
FCliente: TArray<TClienteClass>;
public
property adicional: TArray<TAdicionalClass> read FAdicional write FAdicional;
property cliente: TArray<TClienteClass> read FCliente write FCliente;
destructor Destroy; override;
function ToJsonString: string;
class function FromJsonString(AJsonString: string): TResultClass;
end;

TRootClass = class
private
FResult: TArray<TResultClass>;
public
property result: TArray<TResultClass> read FResult write FResult;
destructor Destroy; override;
function ToJsonString: string;
class function FromJsonString(AJsonString: string): TRootClass;
end;

implementation

{TAdicionalClass}

function TAdicionalClass.ToJsonString: string;
begin
result := TJson.ObjectToJsonString(self);
end;

class function TAdicionalClass.FromJsonString(AJsonString: string): TAdicionalClass;
begin
result := TJson.JsonToObject<TAdicionalClass>(AJsonString)
end;

{TClienteClass}

function TClienteClass.ToJsonString: string;
begin
result := TJson.ObjectToJsonString(self);
end;

class function TClienteClass.FromJsonString(AJsonString: string): TClienteClass;
begin
result := TJson.JsonToObject<TClienteClass>(AJsonString)
end;

{TResultClass}

destructor TResultClass.Destroy;
var
LclienteItem: TClienteClass;
LadicionalItem: TAdicionalClass;
begin

for LclienteItem in FCliente do
LclienteItem.free;
for LadicionalItem in FAdicional do
LadicionalItem.free;

inherited;
end;

function TResultClass.ToJsonString: string;
begin
result := TJson.ObjectToJsonString(self);
end;

class function TResultClass.FromJsonString(AJsonString: string): TResultClass;
begin
result := TJson.JsonToObject<TResultClass>(AJsonString)
end;

{TRootClass}

destructor TRootClass.Destroy;
var
LresultItem: TResultClass;
begin

for LresultItem in FResult do
LresultItem.free;

inherited;
end;

function TRootClass.ToJsonString: string;
begin
result := TJson.ObjectToJsonString(self);
end;

class function TRootClass.FromJsonString(AJsonString: string): TRootClass;
begin
result := TJson.JsonToObject<TRootClass>(AJsonString)
end;

end.

[/code]

 

 

 

Construindo o Servidor RESTServer com exemplos… retornar um TDataset em um JSONObject X “Reflection”.

Para iniciar utilizei o modelo criado pelo delphi: new -> Datasnap REST Application. Criado o projeto alterei a unit abaixo:

GIT com fontes para as dependências

[code lang=”pascal”]

unit ServerMethodsUnit1;

interface

uses System.SysUtils, System.Classes, System.Json,
Data.FireDACJSONReflect,
Datasnap.DSServer, Datasnap.DSAuth, Datasnap.DSProviderDataModuleAdapter,
FireDAC.Stan.StorageJSON, FireDAC.Stan.StorageBin;

type
{$METHODINFO ON}
TServerMethods1 = class(TDataModule)
FDStanStorageJSONLink1: TFDStanStorageJSONLink;
FDStanStorageBinLink1: TFDStanStorageBinLink;
private
{ Private declarations }
public
{ Public declarations }
// original criado pelo DELPHI
function EchoString(Value: string): string;
function ReverseString(Value: string): string;

// passa o codigo do cliente e retorna os dados do cliente
function GetCliente(codigo: int64): TJSONValue; // exemplo retornando um JSONObject
function GetCliente2(codigo: int64): TFDJSONDataSets; // usando Reflection

// retorna na mesma resposta CLIENTE + ITENS
function GetNotaFiscal(ANumero: integer): TFDJSONDataSets;

end;
{$METHODINFO OFF}

implementation

{$R *.dfm}

uses System.StrUtils, FireDAC.ObjectDataSet, Data.db.helper;

function TServerMethods1.EchoString(Value: string): string;
begin
Result := Value;
end;

function TServerMethods1.ReverseString(Value: string): string;
begin
Result := System.StrUtils.ReverseString(Value);
end;

[/code]

Criando as classes a serem carregadas no TDataset usando RTTI:

[code lang=”pascal”]
type
TClientes = class
private
FCodigo: int64;
FNome: string;
FCidade: string;
FDebitos: double;
FEndereco: string;
FEstado: String;
procedure SetCidade(const Value: string);
procedure SetCodigo(const Value: int64);
procedure SetDebitos(const Value: double);
procedure SetEndereco(const Value: string);
procedure SetEstado(const Value: String);
procedure SetNome(const Value: string);
public
property codigo: int64 read FCodigo write SetCodigo;
property Nome: string read FNome write SetNome;
property Cidade: string read FCidade write SetCidade;
property Estado: String read FEstado write SetEstado;
property Endereco: string read FEndereco write SetEndereco;
property Debitos: double read FDebitos write SetDebitos;
end;

TNotaFiscalItens = class
private
FPreco: double;
FCodigo: string;
FQtde: double;
FNome: string;
procedure SetCodigo(const Value: string);
procedure SetNome(const Value: string);
procedure SetPreco(const Value: double);
procedure SetQtde(const Value: double);
public
property codigo: string read FCodigo write SetCodigo;
property Nome: string read FNome write SetNome;
property Qtde: double read FQtde write SetQtde;
property Preco: double read FPreco write SetPreco;
end;

[/code]

Quando o cliente fizer chamada para GetCliente irá passar o código do cliente, internamente o servidor irá procurar no banco de dados e retornar um JSONObject com os dados do cliente. Este processo permite retornar uma informação mais genérica, importante quando os clientes que irão consumir tenham múltiplas linguagens ou múltiplos desenvolvedores que nem sempre serão Delphianos.

[code lang=”pascal”]

function TServerMethods1.GetCliente(codigo: int64): TJSONValue;
// TFDJSONDataSets;
var
ds: TObjectDataSet;
cli: TClientes;
begin
// buscar os dados no banco de dados com codigo passado pelo cliente…

// resposta para o cliente;

// meus dados no firedac
// usei um ObjectDataset somento para não precisar criar uma conexão e um query
ds := TObjectDataSet.Create(self, TClientes); // usa RTTI para mapear coluna do TDataset
try
ds.Open;
ds.append;
with ds do
begin
FieldByName(‘codigo’).Value := 1;
FieldByName(‘nome’).Value := ‘Embarcadero SA’;
FieldByName(‘Endereco’).Value := ‘Rua…xxxx…,10’;
FieldByName(‘Cidade’).Value := ‘Sao Paulo’;
FieldByName(‘Estado’).Value := ‘SP’;
FieldByName(‘Debitos’).Value := 100000.12;
end;
ds.Post;

// retorna um JsonObject
Result := TJSONObject.ParseJSONValue(ds.ToJson);
finally
ds.Free;
end;
end;

[/code]

Se os clientes que irão consumir o serviço forem sempre RestClient de Delphi, então retornar um objeto mais preparado para a estrutura do RestClient pode ser um opção. Retornando um objetos TFDJSONDataSets aumenta os dados a serem retornados ao cliente mas pode facilitar a implementação para os cliente Delphi.

[code lang=”pascal”]
// retorna um objeto FireDAC JSON Reflection
// isto estabelece uma boa integração entre aplicativos que usam FireDAC nos clientes.
// se o cliente não for FireDAC… talves seja interessante pensar em retornar um
// formato mais generico

function TServerMethods1.GetCliente2(codigo: int64): TFDJSONDataSets;
var
ds: TObjectDataSet;
cli: TClientes;
begin
// buscar os dados no banco de dados com codigo passado pelo cliente…

// resposta para o cliente;
Result := TFDJSONDataSets.Create;
// meus dados no firedac
// usei um ObjectDataset somento para não precisar criar uma conexão e um query
ds := TObjectDataSet.Create(nil, TClientes);
try
ds.Open;
ds.append;
with ds do
begin
FieldByName(‘codigo’).Value := 1;
FieldByName(‘nome’).Value := ‘Embarcadero SA’;
FieldByName(‘Endereco’).Value := ‘Rua…xxxx…,10’;
FieldByName(‘Cidade’).Value := ‘Sao Paulo’;
FieldByName(‘Estado’).Value := ‘SP’;
FieldByName(‘Debitos’).Value := 100000.12;
end;
ds.Post;

TFDJSONDataSetsWriter.ListAdd(Result, ‘CLIENTE’, ds);
finally
// ds.Free; — eh destruido pelo Writer
end;
end;

[/code]

Para retornar mais de uma estrutura de informações no mesma chamada, pode-se utilizar TFDJSONDataSets que permite como no exemplo retornar os dados do Cliente e também os dados dos itens da nota fiscal (no exemplo) no retorno da mesma chamada.

[code lang=”pascal”]

// retornando mais de uma tabala na mesma consulta
// retorna CLIENTE e ITENS da nota fiscal
function TServerMethods1.GetNotaFiscal(ANumero: integer): TFDJSONDataSets;
var
ds: TObjectDataSet;
cli: TClientes;
dsItens: TObjectDataSet;
itens: TNotaFiscalItens;
begin
// buscar os dados no banco de dados com codigo passado pelo cliente…

// resposta para o cliente;
Result := TFDJSONDataSets.Create;
// meus dados no firedac
// usei um ObjectDataset somento para não precisar criar uma conexão e um query
ds := TObjectDataSet.Create(nil, TClientes);
try
ds.Open;
ds.append;
with ds do
begin
FieldByName(‘codigo’).Value := 1;
FieldByName(‘nome’).Value := ‘Embarcadero SA’;
FieldByName(‘Endereco’).Value := ‘Rua…xxxx…,10’;
FieldByName(‘Cidade’).Value := ‘Sao Paulo’;
FieldByName(‘Estado’).Value := ‘SP’;
FieldByName(‘Debitos’).Value := 100000.12;
end;
ds.Post;

TFDJSONDataSetsWriter.ListAdd(Result, ‘CLIENTE’, ds);

// usa RTTI para mapear o objeto para TFDMemTable
dsItens := TObjectDataSet.Create(nil, TNotaFiscalItens);
dsItens.Open;
itens := TNotaFiscalItens.Create;
with itens do
begin
codigo := ‘000001’;
Nome := ‘Margarina’;
Qtde := 2;
Preco := 8.5;
end;
dsItens.ObjectList.Add(itens); // adiciona o objeto ao ObjectDataSet

with itens do
begin
codigo := ‘000002’;
Nome := ‘Pao Frances’;
Qtde := 1;
Preco := 15;
end;
dsItens.ObjectList.Add(itens);

TFDJSONDataSetsWriter.ListAdd(Result, ‘ITENS’, dsItens);

finally
// ds.Free; — eh destruido pelo Writer
end;
end;

…..
end.

[/code]

Clone de ObjectDataset-JEDI para FireDAC….

Encontra-se no GIT o código para carregar um TObject ou TClass diretamente em um Dataset.
A implementação faz uso de RTTI para ler as propriedades do objeto e mapeia os tipo para as colunas do TFDMemTable do FireDAC.

Exemplo de uso:

[code lang=”pascal”]

// Exemplo de uma classe para mapear no Dataset
TMinhaClasse = class
private
….
published
property Nome: string read FNome write SetNome;
property id: integer read Fid write Setid;
property valor: double read Fvalor write Setvalor;
property Data: TDatetime read Fdata write Setdata;
property Dinheiro: Currency read FDinheiro write SetDinheiro;
property Cliente: double read FCliente write SetCliente;
end;

…..
uses FireDac.ObjectDataSet;
…..
// iniciando o Dataset com o link da Classe…
var ods:TObjectDataset;
begin
ods := TObjectDataset.Create(self, TMinhaClasse);
//DataSource1.DataSet := ods; // associa o Dataset a um Datasource
ods.Open;
end;

[/code]

Código Fontes no GIT

Lidando com uma lista externa

A classe mantem uma lista interna com os objetos publicando pela propriedade  TObjectDataset.ObjectList,  se você já possui uma lista externa pode utilizar os métodos:

procedure LoadFromList( AList:TList );   // carrega a lista externa para o TDataset
procedure SaveToList( AList:TList );        //  preeche a lista externa com os dados do TDataset;

Emprestando o exemplo do amigo (Marlon)

[code lang=”pascal”]
TCliente;
var
cli : TCliente;
ods : TObjectDataSet;
begin
cli := TCliente.Create;
cli.ID := 1;
cli.Nome := ”Marlon;
cli.Salario := 123.45;
cli.Dt_Nasc := Date;
ods := TObjectDataSet.Create(Self, TCliente);
ods.Open;
DataSource1.DataSet := ods;

// pode acrescentar o registro no Dataset;
ods.append;
ods.ObjectToField(cli); // não precisa fazer free… a lista interna faz a liberação de memoria.
ods.post;

// outra opção seria:
ods.append;
ods.FieldByname(‘id’).asInteger := 1;
ods.FieldByName(‘nome’).asString := ‘Marlon’;

ods.post;

[/code]

 

Contribuição do  Marlon

[code lang=”pascal”]

unit Unit56;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, FireDac.ObjectDataSet,
FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param,
FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf,
Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, Vcl.Mask, Vcl.DBCtrls,
Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Grids, Vcl.DBGrids;

type

TCliente = class
private
FDt_Nasc: TDate;
FSalario: Currency;
FID: Integer;
FNome: String;
procedure SetDt_Nasc(const Value: TDate);
procedure SetID(const Value: Integer);
procedure SetNome(const Value: String);
procedure SetSalario(const Value: Currency);
public
property ID : Integer read FID write SetID;
property Nome : String read FNome write SetNome;
property Salario : Currency read FSalario write SetSalario;
property Dt_Nasc : TDate read FDt_Nasc write SetDt_Nasc;
end;

TForm56 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Button1: TButton;
DBEdit1: TDBEdit;
DBEdit2: TDBEdit;
DBEdit3: TDBEdit;
DBEdit4: TDBEdit;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
ods : TObjectDataSet;
{ Private declarations }
public
{ Public declarations }
end;

var
Form56: TForm56;

implementation

{$R *.dfm}

{ TCliente }

procedure TCliente.SetDt_Nasc(const Value: TDate);
begin
FDt_Nasc := Value;
end;

procedure TCliente.SetID(const Value: Integer);
begin
FID := Value;
end;

procedure TCliente.SetNome(const Value: String);
begin
FNome := Value;
end;

procedure TCliente.SetSalario(const Value: Currency);
begin
FSalario := Value;
end;

procedure TForm56.Button1Click(Sender: TObject);
var
cli : TCliente;
begin
cli := TCliente.Create;

ods.FieldToObject(cli);

Edit1.Text := IntToStr(cli.ID);
Edit2.Text := cli.Nome;
Edit3.Text := CurrToStr(cli.Salario);
Edit4.Text := DateToStr(cli.Dt_Nasc);

end;

procedure TForm56.Button2Click(Sender: TObject);
var
cli : TCliente;
begin
cli := TCliente.Create;

cli.ID := StrToIntDef(Edit1.Text, 0);
cli.Nome := Edit2.Text;
cli.Salario := StrToCurrDef(Edit3.Text,0);
cli.Dt_Nasc := StrToDateDef(Edit4.Text, Date);

ods.Insert;
ods.ObjectToField(cli);
ods.Post;

end;

procedure TForm56.FormCreate(Sender: TObject);
begin
ods := TObjectDataSet.Create(Self, TCliente);
ods.Open;
DataSource1.DataSet := ods;
end;

end.

[/code]

 

As voltas com código legado…

Encontra-se no GIT o código para carregar um TObject ou TClass diretamente em um Dataset.
A implementação faz uso de RTTI para ler as propriedades do objeto e mapeia os tipo para as colunas do TJvMemoryData do JEDI (depende de ter instalado o JEDI-JvMemoryDataSet).

Clone para FireDAC

Exemplo de uso:

[code lang=”pascal”]

// Exemplo de uma classe para mapear no Dataset
TMinhaClasse = class
private
….
published
property Nome: string read FNome write SetNome;
property id: integer read Fid write Setid;
property valor: double read Fvalor write Setvalor;
property Data: TDatetime read Fdata write Setdata;
property Dinheiro: Currency read FDinheiro write SetDinheiro;
property Cliente: double read FCliente write SetCliente;
end;

…..
uses Data.ObjectDataSet;
…..
// iniciando o Dataset com o link da Classe…
var ods:TObjectDataset;
begin
ods := TObjectDataset.Create(self, TMinhaClasse);
//DataSource1.DataSet := ods; // associa o Dataset a um Datasource
ods.Open;
end;

[/code]

Código Fontes no GIT