Delphi save all values from different datasources with 1 save button - delphi

I got this form;
I want to save al of those edits with 1 save button.
But the problem is that those fields all have a different datasource.
Is there somebody who can help me out?

Simple go over all data sources involved and use DataSource.DataSet.Post (assuming the DataSets are already in dsEdit/dsInsert mode).
Note: If your DBMS supports transactions, it would be wise to group all your posts in a single transaction, so that data/relations integrity will not be compromised e.g.:
MyConnObj.BeginTrans;
try
DataSource1.DataSet.Post;
DataSource2.DataSet.Post;
DataSource3.DataSet.Post;
MyConnObj.CommitTrans;
except
MyConnObj.RollbackTrans;
raise;
end;

Related

Live Data in FireDac

Is it possible in FireDac get live data from database (SQL Server in my case) without updating DataSources like it was in Paradox. The closest things I could found was Live Data Window of FDTable, but information is very scanty and I don’t even sure that Live Data Window means that data is updated automatically. I need it for some obvious reasons. For example database sends some alert and user sees it without TTimer or constantly updating some specific DataSource.
I never used LiveDataWindows for any of my programs, but I Think, as you mentioned above, you should give FDTable a try.
Here is the Link on how to set it up correctly on MSSSL Server as well.
Embarcadero docwiki
You can build a little trial app using the code from docwiki:
uses
Windows;
...
// Set locale ID to German phone book collation
FDTable1.FormatOptions.SortLocale := MAKELCID(MAKELANGID (LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT);
// Use the the punctuation and other symbols case insensitive sorting
FDTable1.FormatOptions.SortOptions := [soNoSymbols];
FDTable1.IndexFieldNames := 'NAME';
FDTable1.TableName := 'CUSTOMERS';
FDTable1.Open;

Delphi FireDAC: how to refresh data in cache

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.

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

Delphi Delete all records from FDTable

Iam trying to delete all records in my FDTable component using ,
mytable.Delete;
but no record is getting deleted.
can any one suggest me a way to delete all records in a FdTable.
EDIT
i modified it in this way,
for i := mytable.RecordCount - 1 downto 0 do
begin
mytable.Delete;
end;
mytable.Refresh;
but it is taking lot of time because there a lot rows in my fdtable.
Try
MyTable.EmptyDataSet;
There may be a bit more to do than that, but you don't say how you are populating MyTable in the first place.
Remove all the records in the underlying database table (the best way to do that will depend on the database) and call refresh just once.
If you must do it via TFdTable, use BeginBatch, do your deletes (without refresh), EndBatch and only then Refresh.
mytable.BeginBatch;
for i := mytable.RecordCount - 1 downto 0 do
begin
mytable.Delete;
end;
mytable.EndBatch;
mytable.Refresh;
I would suggest you use a stored procedure for the job and not SQL from your application. Stored procedures are simple to make and blazing fast because they operate directly on the server.
Just create a stored procedure for your table;
sp_deleteall
and do in it a single line of sql:
delete from mytable
From your application,drop a TFDStoredProc on the form, link it to your stored procedure on the server and just call on the procedure
`
sp_deleteall.ExecProc;
To know how many records were deleted just call, after the procedure execution :
ShowMessage(IntToStr(sp_deleteall.RowsAffected) + ' records were deleted.');
Try it ...
Try
as doing delete for all the rows would hamper the performance.
If that does not work then why don you create the dataset runtime and then free the object.
Form fastest to slowest. First two are commands you execute server side.
Close the table and do a SQL DDL command TRUNCATE TABLENAME; and then reopen. This requires exclusive access to the table.
Use a SQL DML command DELETE FROM TABLENAME;. This does not require exclusive access.
Use a loop client side. A lot slower and triggers a lot of events client side.
all you need to do for delete all records on a FDMemTable is
MyTable.Active := False;

SSRS Stored Procedure CASE statement not being returned to dataset

I have a report that is using a Stored Procedure as the dataset. I have a simple case statement in my stored procedure that manipulates a set of captions based on the results in the record.
CASE
WHEN CWLI.CAPTION='Hypo Tax – Medical'
THEN 'Medical Tax'
WHEN CWLI.CAPTION='Hypo Tax Social'
THEN 'Social Tax'
ELSE CWLI.CAPTION
END AS CAPTION,
CASE
WHEN CWD.CAPTION='Hypo Tax – Medical'
THEN 'Medical Tax'
WHEN CWD.CAPTION='Hypo Tax Social'
THEN 'Social Tax'
ELSE CWD.CAPTION
END AS CWDCAPTION,
I see the expected results when I execute the stored procedure in SSMS, as below:
However, in my report I still see "Hypo Tax Social"
I have closed BIDS. I deleted the dataset and added it as a new data set. I have also changed my config file RSReportDesigner.config and changed CacheDataForPreview to false and deleted my .data file.
What could be going wrong?
I searched for rdl.data files and did not return anything. Though I changed my RSReportDesigner.config file Add Key="CacheDataForPreview" Value="false" , I would still expect to find residual .data files. Nevertheless, I rolled back this change to Add Key="CacheDataForPreview" Value="true"
I deleted my data source, my dataset and recreated from within VSS. I then created an external tool to delete these files for me. I get this message when I use my tool.
Could Not Find C:\Users\Pennie\Documents\Visual Studio 2008\Projects\Client*.rdl.data
I still see the correct results (the new CASE captions) in SSMS and the old captions in my report.
I really want to handle this in the Stored Procedure, but I have a deliverable.
Can I manipulate the captions in the expression of my tablix? Currently
the expression is looking for the value from two fields. One field is at a company level of my application (these could be blank). Fields!CAPTION.Value, the other is at the system level (these will never be blank) Fields!CWDCAPTION.Value
Here is my current expression w/o the additional case.
=Iif(Fields!CAPTION.Value="",Fields!CWDCAPTION.Value,Fields!CAPTION.Value)
When I try to add an additional Iif in this expression. I just return True or False.
Thank again.
Pennie
Well this lesson has taught me quite a bit about cache and .data... but the issue was that the idiot developer (me) was calling my test SP in my report.. My test SP did not contain the case statement. Wish I had more exciting news but the truth is easy to prove ;-)
I'm all set.
Pennie
Sounds like you have added the CASE statement after you initially created the dataset. If that is the case you need to re-create the dataset again. Just to be clear not only delete the dataset from the report but also the dataset itself.

Resources