AnyDAC (FireDAC) - Open transaction after TBlobField.GetAsString - delphi

at the moment we are migrating the database component of our Delphi7 application from the BDE components to the AnyDAC (FireDAC) Version 8.0.5 components.
The following prerequisites are given:
On our form we have one TADConnection, one TADQuery and one TADTable. The TADQuery is the MasterSource for the TADTable. No special changes have been made to the settings of the AnyDAC components, so the AutoCommit mode is active.
Furhtermore we have one TDBMemo on our form which is linked to an ftMemo field of the TADTable (Firebird FieldType = Blob / Size = 240 / Subtype = Text)
During the loading of the blob text field content (TBlobField.GetAsString) the TADTable starts automatically an transaction which would not committed.
Is this behavior normal? Do we have any possiblity to avoid this open transaction?
Please note, deactivating of the AutoCommit is no option at the moment.
Any help appreciated.

Yes, that is a normal behavior. So long you are not fetching BLOB data along with the detail tuple, AnyDAC starts an implicit transaction for fetching those BLOB data.

Related

Setting DateTime format in Delphi with Firedac compatible with BDE Application

I am migrating my application from Delphi2007 and BDE to Delphi 10.4 and Firedac. The new application is in testing, the old app is still there for backup, in case the new application fails.
So, I have 2 applications talking to the same database, one with Firedac, the other with BDE.
The following happens:
As soon as Firedac saves a DateTime field (date + time), that record can no longer be changed in the BDE application. (I use TQuery->DatasetProvide->TClientDataset, updatemode WhereAll, no persistent fields in the TQuery)
Probably, Firedac stores the time-part in a format that confuses the BDE/Datasetprovider.
Is it possible to make Firedac store time in a format the BDE does understand?
I know, the solution could be : adding persistent fields (> 100 tables), and setting the providerflag to pfInkey for all primary keys, and adding datasetproviders with updatemode "whereKeyOnly", but I do not want to change that much and spend so much time on the (very big) old (and soon to be deprecated) application that uses BDE.
I tried mappingrules in Firedac. I added 2 rules:
DateTimeStamp-> DateTime, DateTime -> DateTime.
For both rules I tested with values of PrecMax of 4,6,8. I thought maybe this way the time-value is stored with less precision, but this had no effect. Maybe some other value or mapping?
ADDITION
Editing the field with a dbExpress TSQLCOnnection instead of BDE works.
The default persistent field with TQuery is TDateTime, with dbExpress: TsqlTimeStamp. It seems like the "TDateTime" field is incompattible with values stored as a timestamp. The error is raized when apllying updates. Fetching the data is no problem.

Is the ADO Recordset.CacheSize property meaningful for a client-side cursor?

If I have an ADO Connection with CursorLocationType.adUseClient and I use it to open a Recordset, then does setting the Recordset.CacheSize property have any effect?
From CacheSize Property
Use the CacheSize property to control how many records to retrieve at one time into local memory from the provider.
And from The Significance of Cursor Location:
In ADO, call for a client-side cursor by using the adUseClient CursorLocationEnum. With a non-keyset client-side cursor, the server sends the entire result set across the network to the client computer.
It seems to me that setting CacheSize will have no effect for a client-side cursor, because the records are already in local memory. But I can't find any official documentation that explicitly says this. I can only find blog posts like this one that says:
We will be using ClientSide cursors ... The CacheSize tells ADO to cache N number of rows on the cursor. Since we chose to have 10 records per page, I set the cache size to 10. ADO will grab the first 10 records, and cache those. It won't hit the database until you request any past the cached limit.
but this seems to contradict "the server sends the entire result set across the network to the client computer."
So what actually happens?

AnyDac aka FireDac cannot generate update query

I was using UniDac for a long time now and decided to move on to FireDac as it has good Asynch methods after moving on i saw that none of my data editing works anymore it gives me an error:
[FireDAC][Phys]-330. Cannot generate update query. Update table undefined.
What I am trying to do here is i have a TFDStoredProc component who gets all the data from the database and lets me edit it, with unidac I could easily edit the data without any problem like this:
StoredProc.Edit;
StoredProcCreatedID.Value := SomeValue;
StoredProc.Post;
and it worked, but with AnyDac it doesn't, I tried specifying manually the UpdateTable which leads to another problem:
[FireDAC][Phys][ODBC][Microsoft][SQL Server Native Client 11.0][SQL Server]Invalid column name 'CreatedID'.
I am using Microsoft SQL Server 2012 FireDac 8.0 and stored procedures for getting back results any ideas?
P.S.
The query looks like this
SELECT
CreatedBy as CreatedID,
usr.UserName as CreatedBy
FROM
Sales
LEFT JOIN
Users usr ON usr.ID = Sales.CreatedBy
it looks like the FireDac update builder doesn't recognize the aliases on the fields, any help would be appreciated.
Well i figured out what was the issue, it seems that if you specify a alias in the query for a field the Origin property will be set to the alias and not the real field i downloaded CNPack a must have for a delphi developer also its free, ran the component selector and changed all my aliased fields to their real fields and it works, but this is still a big issue in FireDac component because it doesnt recognize the aliased fields, lets hope it will be fixed in the future as to specify for every query what table it should update and what fields that just allot of work if you are migrating from a big project in my case 220+ stored procedures.

FireDAC - Show SQL after Macro Expantion

I am trying to use Macros in FireDAC to Preprocess my SQL Queries. I have a TADQuery object on a Data Module with the SQL set to something like:
Select * from MyTable
join OtherTable on MyTable.Key = OtherTable.Key
&Where
Then in my code I do this:
WhereClause = 'stuff based on my form';
Query.MacroByName('Where').AsRaw := WhereClause;
Query.Open;
This has worked great for complicated queries because it lets me make sure my fields and join conditions are correct using the SQL Property editor.
My problem is when the SQL statements ends up invalid because of my where clause. Is there any way to see the SQL after pre-processing that is going to be executed? Right now I am catching the FireDac errors and showing the SQL that is on EADDBEngineException object. However that is still showing my original SQL with the macros. If I can't get to it after the error happens is there anyway to force the Macro replacement to take place so I can look at the SQL in the debugger to help me see what is wrong.
If it matters I am connecting to a MS Access database with the goal of moving to SQL Server in the near future.
Apart from using Text property, to monitor what SQL is actually going to the database engine, consider using the "FDMonitor" FireDAC utility. According to the DokWiki pages (below):
drop a TFDMoniRemoteClientLink component on your form,
Set its Tracing property to True,
Add the MonitorBy=Xxx connection definition parameter to your existing FDConnection component. You can do this in the IDE object inspector, by selecting your FDConnection component, expanding the Params property, and setting MonitorBy to mbRemote.
Note that the TFDMoniXxxxClientLink should come before TFDConnection in the data module or form creation order, so adjust this by right clicking on the form or data module, then Creation Order, and moving the TFDMoni.. component above the FDConnection.
Also, it's helpful in the options of the TFDMoniXxxxClientLink, to disable most of the events being recorded, otherwise all the data returned is also shown in the FireDAC monitor. Expand the EventKinds property, and turn all the event kinds off, except for perhaps ekConnConnect, ekConnPrepare, and ekCmdExecute.
Then open the FireDAC Monitor from the IDE, (Tools > FireDAC Monitor). Start your app only once the monitor is running. Double click on a trace event (in the Trace Output tab), and you will see the actual SQL sent to the database in the bottom pane.
It also seems likely that adding the EventType of ekConnPrepare as mentioned above, would show you when the query's Prepare is called, but I haven't played enough with it say for sure.
Please see the following pages on the DocWiki for more information:
Overview: FDMonitor
How to: Tracing and Monitoring (FireDAC)
Other FireDAC utilities: Utilities (FireDAC)
(Just to remove this question from list of unanswered questions)
From comments:
Well, I've roughly checked what's happening there and I'm still not
sure if calling Prepare (which is useless for you as I get) is the
minimal requirement to trigger that preprocessing. Though, the
preprocessed SQL, the one which is sent to the DBMS you can access
through the Text property (quite uncommon name for such property). – TLama Feb
21 '14 at 8:18

Delphi: Text-blobs in ClientDataSet on Firebird 2.5 with ODBC

We have faced a very strange problem. We are running a firebird 2.5 database with the following table structure.
CREATE TABLE TEST (
ID INTEGER NOT NULL,
MEMO BLOB SUB_TYPE 1 SEGMENT SIZE 80,
DATO TIMESTAMP
);
ALTER TABLE TEST ADD CONSTRAINT PK_TEST PRIMARY KEY (ID);
We are using Firebird 2.5.1 + ODBC 2.0.0.151 on Windows 7.
We use Delphi XE, with TADOConnection + TADODataSet + TDataSetProvider + TClientDataSet to connect to the database.
The problem is when we insert (or update) a new record into the ClientDataSet and updating the field MEMO. (TMemoField) (This has been working perfekt in FB 1.5 and with all versions of MS SQL server).
Now with a firebird 2.5 database we get the error message "Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another." when running from the Delphi IDE, but no error if we run outside.
The big problem is that the time part of the field DATO is gone when we update the field MEMO. If we don't include the MEMO field, everything is OK.
One other strange thing is that if we use the TADODataSet directly to update the fields, everything works fine. It's only when updated through the ClientDataSet it is a problem.
I have made a small demo project illustrating the problem.
Test.zip (1090 KB):
http://www.consultas.no/u/3037f738
All tips and hints will be highly appreciated!
Best regards,
Bjørn Larsen
Have you tried using TBlobField instead of TMemoField for the blob ?
Sorry, I don't have Delphi available right now to play around locally.

Resources