3

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.

SiBrit
  • 1,460
  • 12
  • 39

2 Answers2

5

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.

SiBrit
  • 1,460
  • 12
  • 39
0

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;
  • 1
    This code is the same as the OP wrote in the question itself, where the OP also explains why it did not work for the components they are using. You should read the question again more carefully; see particularly the very first code snippet they provided. – Ken White May 02 '20 at 19:54