Hello everyone
We just acquired DataAbstract to create our iOS app.
The issue is our database server is a datasnap server, as i’m Kinda new to this whole DataAbstract thing, I need to understand if it’s possible to connect DataAbstract to the datasnap server?
If yes how would you recommend doing it?
If no, then what is the possible solution, as we don’t want to change the server (it handles our desktop client).
Thanks for your help.
No one?
Hi, you should be getting an answer shortly; my colleagues on the Data Abstract team were out of the office over the weekend.
You can use our old article. It may contain some minor differences regarding to DA9 because it was created for DA6,
In this article will be shown how to migrate from Datasnap applications to DataAbstract application.
Migrating from a DataSnap application to Data Abstract_testcase.zip (335.2 KB)
Server-side
This datasnap server uses authentication, provides access to Customer table from Employee.gdb and allows to call custom server methods.
so DataAbstract server will contain two services: LoginService
that will check authentication and DataService
that will be main service.
Creating Server.RODL in Service Builder
It can be made via RemObjects SDK->Turn server into a RemObjects SDK Server
after confirmation, Service Builder
will be launched.
For correct work, these two services should be created as descendants of base DataAbstract services. For this, DataAbstract4.RODL
should be imported into server.RODL:
After this, two new services should be created:
Loginservice
with SimpleLoginService
as the ancestor and DataService
with DataAbstractService
as the ancestor. Also create two operations in DataService:
function EchoString(Value: WideString): WideString;
function ReverseString(Value: WideString): WideString;
Close Service Builder
.
Generation of files from RODL
Call RemObjects SDK->Regenerate Units from RODL
.
These files will be generated:
- NewLibrary_Intf.pas
- NewLibrary_Invk.pas
- LoginService_Impl.pas
- DataService_Impl.pas
ServerDataModule.pas
Create a new datamodule and drop to it:
- TROIndyHTTPServer
- TROBinMessage
- TROInMemorySessionManager
- TDADriverManager
- TDAConnectionManager
- TDAIBXDriver
set this value in Object Inspector:
DAConnectionManager1.DriverManager = DADriverManager1
Click on ROIndyHTTPServer1.Dispatchers
in ObjectInspector and add new dispatcher
also create onCreate event:
LoginService_Impl.pas
Select LoginService_Impl.pas.
Add ServerDataModule into uses section and set in Object Inspector
LoginService.SessionManager = ServerDM.ROInMemorySessionManager1.
Two events are required in this unit:
procedure TLoginService.SimpleLoginServiceLogin(Sender: TObject; aUserID,
aPassword: UTF8String; out aUserInfo: UserInfo;
var aLoginSuccessful: Boolean);
begin
aLoginSuccessful := (aUserID <> '') and (aUserID = aPassword);
if aLoginSuccessful then CreateSession;
end;
procedure TLoginService.SimpleLoginServiceLogout(Sender: TObject);
begin
DestroySession;
end;
DataService_Impl.pas
Select DataService_Impl.pas
drop
- TDASchema
- TDABin2DataStreamer
set properties in ObjectInsector:
DataService.ServiceDataStreamer = DABin2DataStreamer1
DataService.ServiceSchema = DASchema1
DataService.SessionManager = ServerDM.ROInMemorySessionManager1
DataService.RequiresSession = True
DASchema1.ConnectionManager = ServerDM.DAConnectionManager1
and copy content of these methods from ServerMethodsUnit1.pas:
function TDataService.EchoString(const Value: UnicodeString): UnicodeString;
begin
Result := Value;
end;
function TDataService.ReverseString(const Value: UnicodeString): UnicodeString;
begin
Result := StrUtils.ReverseString(Value);
end;
Dbl click on DASchema1, Schema Modeler
will be launched.
create a new connection to Employee.gdb and CUSTOMER table:
Close
Schema Modeler
.
Compile and launch server.
Server-side is ready now.
Client-side
Client side contains login/logout buttons, grid that shows table and two buttons which call custom servers methods.
Select client.dpr and add NewLibrary_Intf.pas from server project to client.dpr
ClientDataModule.pas
Add a new datamodule
Drop
- TROWinInetHTTPChannel
- TROBinMessage
- TRORemoteService
- TDARemoteDataAdapter
- TDABin2DataStreamer
- TDAVCLReconcileProvider
and set properties in Object Inspector:
ROWinInetHTTPChannel1.TargetURL = http://localhost:8099/bin
RORemoteService1.Channel = ROWinInetHTTPChannel1
RORemoteService1.Message = ROBinMessage1
RORemoteService1.ServiceName = DataService
DARemoteDataAdapter1.DataStreamer = DABin2DataStreamer1
DARemoteDataAdapter1.RemoteService = RORemoteService1
DARemoteDataAdapter1.ReconcileProvider = DAVCLReconcileProvider1
click on “Create Data Tables…” in popup menu of DARemoteDataAdapter1.
Login Screen will be shown, type ‘‘UserID=test;Password=test’’ in aLoginString and create CUSTOMERS table in next dialog.
MainForm.pas
Add NewLibrary_intf
and ClientDataModule
into uses section.
Replace old methods in MainForm
:
procedure TForm2.Button1Click(Sender: TObject);
begin
DataModule1.tbl_CUSTOMER.Close;
DataModule1.tbl_CUSTOMER.Open;
end;
procedure TForm2.Button2Click(Sender: TObject);
begin
DataModule1.tbl_CUSTOMER.ApplyUpdates;
end;
procedure TForm2.Button3Click(Sender: TObject);
begin
ShowMessage((DataModule1.RORemoteService1 as IDataService).EchoString(Edit3.Text));
end;
procedure TForm2.Button4Click(Sender: TObject);
begin
ShowMessage((DataModule1.RORemoteService1 as IDataService).ReverseString(Edit3.Text));
end;
procedure TForm2.Button5Click(Sender: TObject);
begin
if not CoLoginService.Create(DataModule1.ROBinMessage1,DataModule1.ROWinInetHTTPChannel1).LoginEx(
UTF8Encode(Format('UserID=%s;Password=%s',[Edit1.Text,Edit2.Text]))) then
showMessage('Problems with login');
end;
procedure TForm2.Button6Click(Sender: TObject);
begin
DataModule1.tbl_CUSTOMER.Close;
CoLoginService.Create(DataModule1.ROBinMessage1,DataModule1.ROWinInetHTTPChannel1).Logout;
end;
Client side is ready.
P.S. Don’t forget to remove old datasnap units from projects
Migrating from a DataSnap application to Data Abstract_testcase.zip (335.2 KB)
Hi thanks for your answer EvgenyK
I already saw this article, it talks about converting the Datasnap server to a DataAbstract server which we would like to avoid, as we don’t want to change the client application, is there a way to connect the DataAbstract client to the Datasnap server without converting it? or at least having the Datasnap and DataAbstract Both side by side on the same server app?
thanks again
Data Abstract client can’t connect to DataSnap server as is because DataAbstract client sends requests in another format in comparing with Datasnap, but you can have DataSnap server and DataAsbtract server in one app - they can use different ports.
Pls review the RO\DataSnap sample - it demonstrates how to use DataSnap technology with Remoting SDK server.
Thanks
I will look into that
can i get this article from the old wiki How to Write a Service Using DataSnap Classes (Delphi)
thanks
This article shows how you can use DataSnap
classes to retrieve data from a database using a remote client and send back changes to update the database. A sample project is provided, which you can download via the link at the bottom of the article.
Start by opening the CDSServerSample.bpg project group.
The server
The server basically consists of a main form and a data module that contains the implementation of the service (CDSService) used in this example.
The CDSService is defined as follows:
ICDSService = interface
['{1F0A5C88-4B51-4D74-B2A9-C850E25E309A}']
function GetData: Binary;
procedure UpdateData(const Delta: Binary);
end;
The GetData
method will read all the data contained in the DBDEMOS table employee.db
and the Binary result will be passed to a TClientDataset used by the client. That TClientDataset will be bound to a TDBGrid and will allow users to browse and edit the data in a disconnected fashion.
The UpdataData
method will then be used by the client to propagate the changes back to the server which, in turn, will update “employee.db
”. If the update fails, an exception will be sent back to the client and no data will be stored.
The data module contained in the unit CDSService_Impl.pas looks like this:
As you can see, there is really nothing special in this data module except for the DataSetProvider
component. This component, part of the DataSnap
framework, is responsible for generating the data returned by the GetData method, and for resolving the changes sent by the client via UpdateData.
This is the implementation of TCDSService’s GetData
:
function TCDSService.GetData: Binary;
var
recsout: integer;
begin
result := BinaryFromVariant(
DataSetProvider.GetRecords(-1, recsout, MetaDataOption + ResetOption));
end;
BinaryFromVariant
is a utility routine that we provide in the uROBinaryHelpers.pas unit. It simply converts OleVariants to Binary (which is a simple TMemoryStream). Refer to the Delphi help file for more information about TDatasetProvider.GetRecords.
Here is the implementation of the UpdateData
method:
procedure TCDSService.UpdateData(const Delta: Binary);
var
errcnt: integer;
begin
DataSetProvider.ApplyUpdates(VariantFromBinary(Delta), 0, errcnt);
if (errcnt>0) then
raise Exception.CreateFmt('There were %d errors', [errcnt]);
end;
Nothing more than transforming the delta of changes received into a variant using VariantFromBinary, and invoking the right method of the dataset provider.
This is all that is needed for the server side.
The client
The client form looks like this:
This is the code attached to the “Get Data
” button:
procedure TClientForm.Button1Click(Sender: TObject);
var
svc: CDSService;
data: Binary;
begin
svc := CoCDSService.Create(ROSOAPMessage, ROWinInetHTTPChannel1);
try
data := svc.GetData;
ClientDataSet1.Data := VariantFromBinary(data);
finally
data.Free;
end;
end;
In the first line we create a proxy to our remote service, then we invoke its GetData method and, using the functions of uROBinaryHelpers.pas, we fill the TClientDataset.Data variant.
After this method executes, you will see the TDBGrid populated with all the records of the remote “employee.db
” table.
This is the code attached to the “Update Data” button:
procedure TClientForm.Button2Click(Sender: TObject);
var
svc: CDSService;
delta: Binary;
begin
if (ClientDataSet1.ChangeCount= 0 ) then begin
MessageDlg('There are no changes pending', mtError, [mbOK], 0);
Exit;
end;
delta := NIL ;
try
delta := BinaryFromVariant(ClientDataSet1.Delta);
svc := CoCDSService.Create(ROSOAPMessage, ROWinInetHTTPChannel1);
svc.UpdateData(delta);
finally
delta.Free;
end;
end;
Conclusions
This example has shown how easy it is for a system written with the Remoting SDK
to manually take advantage of DataSnap’s classes.
Hello EvgenyK!
I looked into the sample you sent me
I’m having troubles understanding how I can have datasnap connectivity along with DataAbstract connectivity in the same server without heavily modifying the server and modifying my current client which I wanted to avoid.
Please any help or indication would be appreciated.
Hi,
Can you describe your current server and what you want to reach finally?
You can post this info to support@ in case this is private info
The current server is a basic SOAP datasnap server (it will evolve to a REST datasnap)
We have a client (pc) that connects to this server and everything is working perfectly, we decided to create a natif iOS App on Xcode and not on Rad studio, and we bought DA to do that, but we realised that it could not connect to datasnap directly and we needed to modify the server ( my original post).
We basically wanna include DA connectivety to the server without messing with the datasnap connection that works
You can have DA server and DataSnap server in one app.
they can handle different ports.
You can create a new DAD server with wizard and then add created files to your project.
also you need to copy these lines from created project into your one:
{#ROGEN...
{$R RODLFile.res}
Thanks EvgenyK we will try that,what is the DAD server for you? is there any topic created about that in the old wiki?
DAD server = Data Abstract for Delphi server
so you can use our wizard, File->New->Other->Data Abstract->VCL Application
(or FMX appliication)
Hello EvgenyK
thanks again, but i need your answer on some important questions, it’s crucial cause it will decide if we will continue using DA or not:
1- Could you confirm if each datasets needs to be recoded using a Data Abstract compatible dataset, including the business logic behind these datasets, or do we only need to drop additinal components to open a new DA interface ?
The problem i am having is that i want to be sure i won’t have to recode the server again, or that i won’t have to re-implement all lmy buisness logic, etc…
what business logic you have: client-side or server-side?
can you describe it?
Data Abstract supports both (client-side and server-side) business logic. this logic can be coded directly in code or can be added via JavaScript code inside Schema Modeler.
Data Abstract tables and fields have almost the same properties/methods as usual TDataset and TField so pretty sure you can use your client-side business logic w/o big changes.
also tables have the Dataset property and fields have the BoundedField property that gives access to nested TDataset/TFields accordingly
I will put this here so people can have it if they are in the same case:
we have our PC client /server that was developed on Delphi to perform operations on a firebird database.
Now we need to develop an iOS app that would connect to the same server, and perform some of the same operations but on a mobile Device.
The server includes the Buisness logic and includes all the database management, it’s a datasnap SOAP server.
The iOS app would have to connect to that server and respect all the restrictions the server impose.
Now the problem we are facing is that either we develop the iOS app on RAD Studio and it works with our sever without any modifications.
OR we code on Xcode and use DataAbstract to manage the middle tier connection.
The problem is the Server, we absolutely need to connect to the same server and respect everything that has been coded into it since the beginning.
Adding DataAbstract to the server and making it a hybrid server would be a perfect solution, only if you could confirm if each datasets needs to be recoded using a Data Abstract compatible dataset, including the business logic behind these datasets, or if we only need to drop additinal components to open a new DA interface ?
Data Abstract server can connect to Firebird w/o any problem.
you can connect to FireBird via your favorite Direct Component Library (DAC). DA supports most popular DACs (FireDAC/AnyDAC, IBX, IBDAC, UniDAC, etc).
can you give some code snippet with your business logic?
as a temporary solution during migration, you can register all your datasnap datasets in DataAbstractService.ExportedDataTables
collection so they will work like they were declared in Schema Modeler. In this case, all business logic will be reused in case it was used via dataset’s events.
If your business logic was implemented something else, like via events of datasnap module, it may not work.
We are not migrating as we still need datasnap to connect our PC client to the server.
We need both, and we need them to cohabitate.
We don’t want to code all our settings in the server for them to work with DataAbstract, I thought DA would behave like a door to the server and then the server manages the rest as it usually do
DataAbstract can transport
select, insert, update, delete requests from client to server and later to DB server. this is no problem at all.
in your case, as I understand, the problem with porting server-side business logic from Datasnap to DA part.
can you give to me some sample of your business logic and I will say how it can be ported
I have this question still unanswered, could you confirm if each datasets needs to be recoded using a Data Abstract compatible dataset, including the business logic behind these datasets, or if we only need to drop additinal components to open a new DA interface ?
if you declare your tables in Schema modeler (it can be easily done with drag&drop), then we only need to drop additinal components to open a new DA interface
if you want to add some business logic then you need add it manually to server-side for DataAbstract service.
Could you give us pointers what are the additional components needed to be dropped to open a new DA interface in the Datasnap server?
A tutorial would be mush appreciated
use our wizard: File->New->Other->Data Abstract->Client module for VCL|FMX application
it will ask you for server address and will create required Data Abstract components