We have been using dbExpress for years. But too many bugs go unfixed and we are now forced to switch to ADO.
As we have been switching to ADO, we have found things that dbExpress handled differently than ADO. For instance, when pulling calculated fields, or data from a CTE query (which combines data from multiple tables into a single dataset), the TADOQuery flags each field as read-only. dbExpress didn't do that.
Now our client app won't let the read-only records be changed in any way, and all attempts to remove the read-only field attribute have failed.
Here is some contrived code to demonstrate the issue:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, Data.Win.ADODB, Datasnap.DBClient, Data.DB, ActiveX;
var
con: TADOConnection; cds: TClientDataSet; qry: TADOQuery; i: Integer;
begin
try
CoInitialize(nil);
try
begin
con := TADOConnection.Create(nil);
try
con.ConnectionString := 'Provider=SQLNCLI10.1;Integrated Security=SSPI;Initial Catalog=tempdb;Data Source=localhost';
cds := TClientDataSet.Create(nil);
try
cds.DisableStringTrim := True;
cds.ReadOnly := False;
qry := TADOQuery.Create(nil);
try
qry.Connection := con;
qry.SQL.Text := 'select 1 as ID, ''test'' as aString';
cds.SetProvider(qry);
cds.Open;
{ Attempting to change read-only flag -- nothing changes! }
for i := 0 to cds.FieldDefs.Count - 1 do
cds.FieldDefs[i].Attributes := cds.FieldDefs[i].Attributes - [faReadonly];
cds.SaveToFile('c:\test.xml', dfXML);
finally FreeAndNil(qry); end;
finally FreeAndNil(cds); end;
finally FreeAndNil(con); end;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
finally
CoUninitialize;
end;
end.
Which produces this file:
<?xml version="1.0" standalone="yes"?>
<DATAPACKET Version="2.0">
<METADATA>
<FIELDS>
<FIELD attrname="ID" fieldtype="i4" readonly="true"/>
<FIELD attrname="aString" fieldtype="string" readonly="true" WIDTH="4"/>
</FIELDS>
<PARAMS/>
</METADATA>
<ROWDATA>
<ROW ID="1" aString="test"/>
</ROWDATA>
</DATAPACKET>
Notice the readonly="true" in the field defs.
Question
Our framework uses a generic TADOQuery and TClientDataSet components to pull and transfer the data from the database to the client app. The TADOQuery derives the field definitions from the data that is pulled from the database. So we can't setup the fields in advance, before pulling the data, and the field definitions seem to be static after pulling the data...
We don't save the data from the TClientDataSet to an XML file for real. It's just used here for demonstrative purposes, and it illustrates that the fields are flagged as read-only.
Does anyone know how to tweak the above code so the saved XML will not have the read-only="true" attribute? Our need is to allow users to edit all fields in the TClientDataSet.