Delphi FireDAC: how to refresh data in cache - delphi

i need to refresh data in a TFDQuery which is in cached updates.
to simplify my problem, let's suppose my MsACCESS database is composed of 2 tables that i have to join.
LABTEST(id_test, dat_test, id_client, sample_typ)
SAMPLEType(id, SampleName)
in the Delphi application, i am using TFDConnection and 1 TFDQuery (in cached updates) in which i join the 2 tables which script is:
"SELECT T.id_test, T.dat_test, T.id_client, T.sample_typ, S.SampleName
FROM LABTEST T
left JOIN SAMPLEType S ON T.sample_typ = S.id"
in my application, i also use a DBGrid to show the result of the query.
and a button to edit the field "sample_typ", like this:
qr.Edit;
qr.FieldByName('sample_typ').AsString:=ce2.text;
qr.Post;
the edition of the 'sample_typ' field works fine but the corresponding 'sampleName' field is not changing (in the grid) after an update.
in fact it is not refreshed !
the problem is here: if i do refresh of the query, an exception is raised: "cannot refresh dataset. cached updates must be commited or canceled
and batch mode terminated before refreshing"
if i commit the updates, data will be sent to database and i don't want that, i need to keep the data in cache till the end of the operation.
also if i get out of the cache, data will be refreshed in the grid but will be sent to the database after qr.post and i don't want that.
i need to refresh data in the cache. what is the solution ?
Thanks in advance.

The issue comes down to the fact that you haven't told your UI that there is any dependency on the two fields - it clearly can't know how to do the join itself without resubmitting it so if you don't want to send the updates and reload you will have a problem.
It's not clear exactly what you are trying to do, but these two ideas may help you.
If you are not going to edit the fields in the SAMPLEType tables (S) then load the values from that table into a lookup table. You can load this into a TFDMemTable. You can use an adapter which loads from a query. Your UI controls can then show the value based on the valus looked up in your local TFDMemTable. Dependiong on the UI control this might be a 'LookupField' or some such.
You may also be able to store your main data in a TFDMemTable with an Adapter - you can specify diferent TFDCommands to read the whole recordset, refresh a record, update, insert and delete a record. The TFDCommands can act on multiple tables for joined recordsets like this. That would automatically refresh the individual record for you when you post it.

Related

MS Access Form Text Boxes Freeze

I have a weird situation with my MS Access 2016 split database.
The back-end is a Azure SQL server DB, the front-end are distributed accde files.
I have a form bound to a linked table with several sub-forms in it.
The form is used to edit single records of the main table.
With some records all works fine ("good") but with some other records ("bad") the text boxes freeze, not allowing any edits.
No error messages, they just seem to be locked but the locked property of the text boxes control is set to false. (I've checked this in runtime)
What I've tried so far:
I can edit all records directly in the linked table
The properties of the form and controls in both "good" records and
"bad" records are the same
I can change the values of check and combo boxes and update the "bad"
records
The BIT column has a default value of 0 and nulls are not allowed (no
NULLS in the table for this field)
I'm running out of ideas. Any help will be much appreciated.
I've figured it out, so i'll leave the solution in case someone hits the same issue.
I have a subform with a browser control. All i had to do was to add the following line at the end of the main form loading sequence:
Me.SF_WEB_BROWSER.SetFocus

Delphi 10 -how to delete detail records automatically when delete master?

I'm using Delphi 10 with Firedac , I have with two tables in a Master-Detail configuration , A(Document) and B(DocDetail) . In my Form I have two DBgrids, linked to each Datasource respectively. I want a configuration, if possible, that delete all records items in table DocDetail when I delete its corresponding Master record in the master DBgrid. Is there any configuration in the table FDTable component that does such action ? Or there any other way to do delete master - delete detail in Delphi side ? (I know that it is possible to do it in database side through a constraint delete cascade). Thanks for your help.
The properties you are looking for on the TFDQuery component are FetchOptions.DetailCascade and/or FetchOptions.DetailServerCascade
From the help on DetailServerCascade
When DetailServerCascade is False, then FireDAC posts client-side
cascading changes to the database. The client-side cascading changes
are performed when DetailCascade is True. So DetailServerCascade
should be used together with DetailCascade.
If you are using CachedUpdates you may also need a TFDSchemaAdapter component. This CentralizedCachedUpdates Sample page list all of the steps need to setup the components when using cached updates.
I am using this on one form with good results. It was a little bit picky to get it all setup correctly. Basically every DataSet involved in the update needs to point to one common TFDSchemaAdapter component. Then any Master datasets need to have their FetchOptions.DetailCascade set to true to ensure that the rows are correctly deleted from the child datasets

Fetching only changed SQL result from server

My iOS application fetches some photos, tags and comments from web server. I want it to fetch only changed or new added data. I don't want it to fetch repeated data again and again.
I use SDWebImage for pictures. But text are based on SQL text.
How could I understand the result of the SQL is changed or not? What kind of technique
should I use?
Is there a third party library for client side SQL catching?
I think it is not iOS related question technically. You should query always with the last queried timestamp.
Like:
SELECT * FROM comments WHERE last_modified > last_queried_timestamp;
last_modified field should store the timestamp of the last modification date or the timestamp of creation and the last_queried_timestamp parameter is the timestamp of the last date when you queried from the server.
This way you will not get twice the same changes.
(Unless you want it)

Updating core data performance

I'm creating an app that uses core data to store information from a web server. When there's an internet connection, the app will check if there are any changes in the entries and update them. Now, I'm wondering which is the best way to go about it. Each entry in my database has a last updated timestamp. Which of these 2 will be more efficient:
Go through all entries and check the timestamp to see which entry needs to be updated.
Delete the whole entity and re-download everything again.
Sorry if this seems like an obvious question and thanks!
I'd say option 1 would be most efficient, as there is rarely a case where downloading everything (especially in a large database with large amounts of data) is more efficient than only downloading the parts that you need.
I recently did something similiar.
I solve the problem, by assigning an unique ID and a global 'updated timestamp' and thinking about 'delta' change.
I explain better, I have a global 'latest update' variable stored in user preferences, with a default value of 01/01/2010.
This is roughly my JSON service:
response: {
metadata: {latestUpdate: 2013...ecc}
entities: {....}
}
Then, this is what's going on:
pass the 'latest update' to the web service and retrieve a list of entities
update the core data store
if everything went fine with core data, the 'latestUpdate' from the service metadata became my new 'latest update variable' stored in user preferences
That's it. I am only retrieving the needed change, and of course the web service is structured to deliver a proper list. Which is: a web service backed by a database, can deal with this matter quite well, and leave the iphone to be a 'simple client' only.
But I have to say that for small amount of data, it is still quite performant (and more bug free) to download the whole list at each request.
As per our discussion in the comments above, you can model your core data object entries with version control like this
CoreDataEntityPerson:
name : String
name_version : int
image : BinaryData
image_version : int
You can now model the server xml in the following way:
<person>
<name>michael</name>
<name_version>1</name_version>
<image>string_converted_imageData</image>
<image_version>1</image_version>
</person>
Now, you can follow the following steps :
When the response arrives and you parse it, you initially create a new object from entity and fill the data directly.
Next time, when you perform an update on the server, you increase the version count of an entry by 1 and store it.
E.g. lets say the name michael is now changed to abraham, then version count of name_version on server will be 2
This updated version count will come in the response data.
Now, while storing the data in the same object, if you find the version count to be same, then the data update of that entry can be skipped, but if you find the version count to be changed, then the update of that entry needs to be done.
This way you can efficiently perform check on each entry and perform updates only on the changed entries.
Advice:
The above approach works best when you're dealing with large amount of data updation.
In case of simple text entries for an object, simple overwrite of data on all entries is efficient enough. And this also keeps the data reponse model simple.

TClientDataSet and processing records with StatusFilter

I'm using a TClientDataSet as a local dataset without the provider concept. After working with it a method is called that should generate the corresponding SQL statements using the StatusFilter to resolve the changes (generate SQL basically).
This looked easy initially after reading documentation (set StatusFilter to [dsInsert], process all inserts SQL, set StatusFilter to [dsModified] process all updates, the same with deletes) but after a few tests now looks far from trivial, for example:
If I add a record, then edit it: setting the StatusFilter to [dsInserted] displays it, but with the original data.
If I add a record, then edit, then delete it: the record appears with StatusFilter set to [dsInserted] and [dsModified] also.
And other similar situations..
1) I know that if first I process all inserts, then all updates then all deletes the database will be updated in the correct state but it looks far from right this approach (generating useless sql statements).
2) I've tried to access the PRecInfo(ClientDataSet.ActiveBuffer + ClientDataSet.RecordSize).Attribute information (dsRecNew, dsRecOrg, etc.) but still not manage to resolve the logic.
3) I can program the logic to resolve it, for example before processing and insert, set StatusFilter to [dsDeleted], and locating by the primary key if the record to see if its deleted thereafter.. the same with edits, before inserting, checking if the record was updated after so the insert sql in the updated version and so on.. but it should be more easy..
¿Did someone tried to solve this in an elegant and straightforward way? ¿I'm missing something? Thanks

Resources