Delphi Datasnap: How to manually build dataset when using a TDatasetProvider - delphi

I would like to manually build the dataset used by a TDatasetProvider to return the data to the client.
The SQL request is taking a long time to run as a query and I am trying to speed up things by splitting the logic in code and using a kbmMemtable to hold my data before returning it to the client.
Can I do this:
kbmMemtable -> TDatasetProvider -> TClientDataset
If this can be done, in what event of my TDatasetProvider should I set the data in the memtable ?
Using Delphi XE

you could do it in BeforeGetRecords/OnGetData event handler or even elsewhere

Related

How to fix the DevExpress TcxGrid GridMode using a TSQLDataSet linked to a TSQLQuery?

I'm trying to load about 500k+ data linked to an Oracle DB on my TcxGrid, I want to make the process faster using the GridView "GridMode" property, but I need to do that using a TSQLQuery (DBExpress Component) and it just doesn't work, Gridmode seems inoperable (doesn't load data faster on the Grid, doesn't load custom quantity of records using the "BufferCount" property, etc.)
Here I created a TSQLQuery component and used a query script for my 500k table (for performance purposes I just got 500 values but I need to load 500k+):
TSQLQuery
When I link the TSQLDataSet to the Grid and activate the TSQLQuery it shows all the records from the query, even if the GridMode is TRUE and the GridModeBufferCount is 5
GridWithTSQLQuery
On the other hand, when I use a TQuery, the GridMode just works properly, in this case I had to open SQL Explorer, make the connection and assign that connection to the TQuery DataBase property:
SQLExplorer
Here I show my TQuery with the values mentioned before:
TQuery
And when I activate my TQuery.. voilá:
GridWithTQuery
What I'm doing wrong? or do I need to do more things on my TSQLQuery besides linking it to my dataset and then linking the dataset to the grid?
It's impossible that a very old Tquery can do this and not a newer dbExpress component
Thank you so much guys

Run-time Equivalent to Assign Local Data... for TClientDataSet and TSQLQuery

The TSQLQuery class is unidirectional, so for it to be used as a source for a data-bound TDBGrid, a TClientDataSet needs to be linked between the TSQLQuery and the TDataSource that the TDBGrid is bound to.
I can connect the TSQLConnection and make the TSQLQuery active at design-time, with specified params, and then I can right-click on the CDS and choose the "Assign Local Data..." option to have it grab the data from the TSQLQuery, which then appears in the TDBGrid via the linked TDataSource.
The amount of time between choosing "Assign Local Data..." and the data actually appearing in the grid is very short, so I am looking for the way to replicate this at run-time.
Supposedly, I can set the Data property of the CDS to the Data of the source, but a TSQLQuery has no Data property. There was a post about using a provider, but
DataSetProvider1.DataSet := SQLQuery1;
ClientDataSet1.Data := DataSetProvider1.Data;
throws an access violation,
I did implement the data copy by looping through the TSQLQuery and appending the records to the TClientDataSet, but that was a lot slower than the "Assign Local Data...".
[Edit 1]
All the components I need are hooked up at design-time, and I can make the TSQLConnection active, then the TSQLQuery, then the TClientDataSet and the TDBGrid displays the data from the parameterised query defined in the TSQLQuery.
In the OnChange event of a TComboBox, I need to refresh the query using a different parameter and have the grid show the relevant results, so I Close the TSQLQuery, change the ParamByName value, Open the TSQLQuery and then call ClientDataSet1.Last to highlight the last row in the grid.
That gives me a "Cannot perform this operation on a closed dataset" error, so I use
ClientDataSet1.Active := true;
but that throws an "Access Violation".
All the examples I can find are all about dropping components onto a form, linking them together, and they work. Well, yes they do, but I need to change properties in code at run-time and still have it work, which it just refuses to do.
This is really beginning to frustrate me.
[Edit 2]
So I followed the example on the Embarcadero site for building a VCL Forms dbExpress Database Application, substituting my database connection details for the Interbase one the example uses.
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Building_a_VCL_Forms_dbExpress_Database_Application
In the designer, everything looked fine and the grid was showing the results from the query, but when I went to run it using F9, I was getting an "Access Violation" thrown from within TCustomClientDataSet.InternalCheck.
Turns out this is a known MIDAS.DLL versioning problem and can be resolved by including MIDASLib in the uses clause of the form. It is just unfortunate that the Datasnap.DBClient code is still throwing Access Violations instead of proper messages, especially since this problem was reported in 2013.
You can use this code. Just change TUniConnection and TUniQuery to what You are using:
Procedure CdsAssignTable(aTableName:String; aCds : TClientDataSet; aCon
:TUniConnection );
Var
aQUery : TUniQuery;
aProvider : TDataSetProvider;
begin
if aCon=Nil then raise Exception.Create('aCon=Nil');
if aCds=Nil then aCds:=TClientDataSet.Create(aCon.Owner);
aQUery:=TUniQuery.Create(Nil);
aQUery.SQL.Text:='select * from '+aTableName;
aQUery.Connection:=aCon;
aQUery.Open;
aProvider:=TDataSetProvider.Create(Nil);
aProvider.DataSet:=aQUery;
aCds.Data:=aProvider.Data;
FreeAndNil(aProvider);
FreeAndNil(aQUery);
End;

Set up SQL Database table in Delphi with TDBGrid (Unidirectional error)

How can i set the whole table of a database to show in my delphi form? Using TDBGrid i presume; but when I configure the data source (connected to a query) I receive an error message about it being Unidirectional. I've heard about a Clientdataset but that didnt seem to work. Could i have some clear instructions on how to do this please? Thank you in advance, Toby.
You say you are using TSQLQuery. This is one of the dbExpress components which are designed to be Unidirectional only (except the TSimpleDataSet). You either have to connect the TSQLQuery to a TDataSetProvider and TClientDataSet or change your query component to one that will buffer the data locally.
To use TDataSetProvider and TClientDataSet:
Set the DataSet property of TDataSetProvider to the SQLQuery.
Set the ProviderName property of the TClientDataSet to the DataSetProvider.
When the ClientDataset is opened, it will contain the data from your SQLQuery.
Set the DataSet Property of your TDataSource to the ClientDataset so the data can be displayed in your DBGrid.
Since you appear to be new to using databases with Delphi, I would recommend you use a different query component, because using the TDataSetProvider and TClientDataSet can be complicated. I suggest
TSimpleDatSet in dbExpress,
TADOQUery or TADODataset in dbGo,
TQuery in BDE (not recommended),
TFDQuery in FireDAC, or
other third party query components.

Change a FireDAC query SQL string from DataSnap client

I have set up a client connecting to a DataSnap Server in Delphi XE7. I need to send a SQL string created on the client to the server to be executed against a Firebird DB. I am using FireDAC, but I get similar results if I use DB Express.
I have TFDPhysFBDriverLink -> TFDConnection -> TFDQuery -> TDataSetProvider on the server.
I have TSQLConnection -> TDSProviderConnection -> TClientDataSet -> TDataSource -> DBGrid on the client
The TFDQuery seems to require a SQL.Text value at design time. (e.g. select * from Cust_Master) I can send the SQL string (e.g. select * from Proj_Master) back to the server fine and load it into the TFDQuery, and if I check the rows affected before and after I change the SQL.Text, I get the right number of rows returned for the customers and the projects queries. The problem is that on the client side, I only get the results of the design time SQL i.e. customers, not the SQL I sent to the server i.e. projects being displayed in the grid. I do call ClientDataSet.Refresh after sending the SQL to the server.
I need to be able to send various SQL queries back to the server, I can't have them all defined at design time. Am I using the right components to achieve this?
You have to close and reopen the ClientDataSet. A simple Refresh won't do.
You need to set DSServer's lifecycle to Invocation or create the FBQuery directly in the ServerMethods' class function. I recommend the second one though.
Check TDataSetProvider->Options->poAllowCommandText is checked

DBGrid not show records

Im try populate grid in Delphi, with values from database. For now, i have a TSQLConnection, TSQLQuery, TDataSource and TDBGrid.
The components are associated as follows:
1) myTDBGrid DataSource: myTDataSOurce
2) myTDataSource DataSet: myTSQLQuery
3) myTSQLQuery Connection: myTSQLConnection
When compile and run a error message broke the application:
Operation not allowed on a unidirectional dataset
Any ideas ?.
This is standard behaviour for dbExpress: all TSQLDataSets are unidirectional and a TDBGrid cannot handle those.
The solution is to use a TClientDataSet connected to a TDataSetProvider, which itself connects to TSQLQuery.
May I suggest reading the dbExpress tutorial?
Thanks for all. Im using the next article: Building aVCL Forms dvExpress and works.

Resources