Firedac Firebird master-detail scenario - delphi

I have master detail
CachedUpdates for the master true
CachedUpdates for the detail true
DetailCascde for the detail true
The master deals with one record:
select * from orders where order_id=:order
First I pass -1 as dummy parameter to get an empty master record:
orders.Close;
orders.Params[0].AsInteger := -1;
orders.Open;
Than I fill the order id with -1 to build the relationship between the master and the detail:
orders.Append;
orders.Fields[0].AsInteger := -1;
orders.Post;
I insert into the detail successfully with Append and Post
The problem is in the Firebird database I have this line on before insert trigger for the master
new.order_id = coalesce((select max(order_id) from orders) + 1, 1);
I ApplyUpdates
Orders.ApplyUpdates(-1);
dOrder.ApplyUpdates(-1);
So when I ApplyUpdates for the master, the detail won't apply because the master id is altered by the server.
How to solve such scenario?

Related

Create stored procedure to update table from another server

I have two servers. I copied the table "Response_Master_Incident" on cadarchive server and duplicated it into the ucpdapps2 server and named it "Master_Incident_For_ProQA". When I duplicated it I only selected certain columns to duplicate (since I didn't need all the columns from "Response_Master_Incident").
Now I am trying to create a stored procedure to update the data from "Response_Master_Incident" to "Master_Incident_For_ProQA" pulling over only those select columns.
create procedure UpdateProQATable
as
begin
Select [ID]
,[Master_Incident_Number]
,[Response_Date]
,[Problem]
,[MethodOfCallRcvd]
,[CallTaking_Performed_By]
,[EMD_Used]
,[Determinant]
,[ProQa_CaseNumber]
,[ProQa_CaseNumber_Fire]
,[ProQa_CaseNumber_Police]
,[MachineName]
into Master_Incident_For_ProQA
from Response_Master_Incident where EMD_Used = '1'
end
When I run this stored procedure I get this error
"Msg 208, Level 16, State 1, Procedure UpdateProQATable, Line 4 [Batch Start Line 2]
Invalid object name 'Response_Master_Incident'."
How do I resolve this error. And is there a way to have the procedure update the table where the "Response_Date" is a date from yesterday and not all the data from the "Response_Master_Incident" table?
So I figured it out. I needed to go to Databases/Server Objects/Linked Servers and link the server that has the data I needed to pull over to the server that was getting the data.
After I did that I corrected my script as suggested in the above comment but also added script to delete all the data currently in the table, insert new data, and filtered the new data by the column of EMD_Used and the Response_Date as yesterdays date. After doing this the desired result was met.
delete from Master_Incident_For_ProQA
insert into [ucpdapps2].[ProQAUsage].[dbo].[Master_Incident_For_ProQA]
([ID]
,[Master_Incident_Number]
,[Response_Date]
,[Problem]
,[MethodOfCallRcvd]
,[CallTaking_Performed_By]
,[EMD_Used]
,[Determinant]
,[ProQa_CaseNumber]
,[ProQa_CaseNumber_Fire]
,[ProQa_CaseNumber_Police]
,[MachineName])
Select [ID]
,[Master_Incident_Number]
,[Response_Date]
,[Problem]
,[MethodOfCallRcvd]
,[CallTaking_Performed_By]
,[EMD_Used]
,[Determinant]
,[ProQa_CaseNumber]
,[ProQa_CaseNumber_Fire]
,[ProQa_CaseNumber_Police]
,[MachineName] FROM [cadarchive].[Reporting_System].[dbo].[Response_Master_Incident] where [EMD_Used] = 1 and [Response_Date] >= DATEADD(day, -1, CONVERT(date, getdate())) AND
[Response_Date] < CONVERT(date, getdate())

How to initiate tables lock for stored procedure in Azure Synapse Analytics?

Currently, I encountered an issue on Azure Synapse Analytics. I have a parent_cust_industry table which is full refresh - The table loads using stored procedure as below:
CREATE PROCEDURE [test].[test_proc] AS
BEGIN
-- LOAD TYPE: Full refresh
IF EXISTS (SELECT 1 FROM sys.tables WHERE SCHEMA_NAME(schema_id) = 'test' AND name = 'test_ld' )
BEGIN
DROP TABLE [test].[test_ld]
END
ELSE IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE SCHEMA_NAME(schema_id) = 'test' AND name = 'test_ld' )
BEGIN
CREATE TABLE [test].[test_ld]
WITH
(
DISTRIBUTION = REPLICATE
, CLUSTERED COLUMNSTORE INDEX
)
AS
SELECT CAST(src.[test_code] as varchar(5)) as [test_code],
CAST(NULLIF(src.[test_period], '') as varchar(5)) as [test_period],
CAST(NULLIF(src.[test_id], '') as varchar(8)) as [test_id]
FROM [test].[test_temp] as src
END
IF NOT EXISTS ( SELECT 1 FROM sys.tables WHERE SCHEMA_NAME(schema_id) = 'test' AND name = 'test_hd' )
BEGIN
RENAME OBJECT [test].[test] TO [test_hd]
END
IF NOT EXISTS ( SELECT 1 FROM sys.tables WHERE SCHEMA_NAME(schema_id) = 'test' AND name = 'test' )
BEGIN
RENAME OBJECT [test].[test_ld] TO [test]
END
IF EXISTS ( SELECT 1 FROM sys.tables WHERE SCHEMA_NAME(schema_id) = 'test' AND name = 'test_hd' )
BEGIN
DROP TABLE [test].[test_hd]
END
END
;
The error happens when there is another stored procedure runs at the same time to load data to another table and it requires the [test].[test] table which cause invalid object for [test].[test].
Normally, the [test].[test_proc] would finish the data load first before other store procs depend on it. But in rare occasion, the data is considerably large, it took more time to process and can cause the invalid object error.
Is there a locking mechanism that I can apply to the stored procedure [test].[test_proc] so that if the two store procs happen to run at the same time, the [test].[test_proc] would finish first then the remaining store procedure can start reading the data from [test].[test] table ?
As you do not have access to traditional SQL Server locking procs like sp_getapplock and the default transaction isolation level of Azure Synapse Analytics, dedicated SQL pools is READ UNCOMMITTED you have limited choices.
You could route all access to this proc through a single Synapse Pipeline and set its concurrency setting to 1. This would ensure only one pipeline execution could happen at once, causing subsequent calls to the same pipeline to queue up.
Set the pipeline concurrency in the Pipeline settings here:
So you could have a single main pipeline that routes to others, eg using the Switch or If activities and ensure the proc cannot be called by other pipelines - should work.

FireDAC Master-Details Cached Updates not work correctly

I have problem with master-details in FireDAC. I have four TFDQueries
master qrPerson
3 details qrAddress, qrPhone, qrEmail
For each of them
SQL is simple query select * from <table>
existing corresponding DataSource
CachedUpdates = true
Connection = conMain
SchemaAdapter = saPerson
Transaction = trMain
UpdateTransaction = trMain
event OnNewRecord for get new ID
For details
FetchOptions.DetailCascade = true
Master = dsPerson
MasterFields = ID_CONTACT
IndexFieldNames = ID_CONTACT
Before save data I get for each of them DataSet.State = dsInsert. I call qrPerson.Post (master) and only one detail (qrEmail) has UpdatesPending = true. The other two details (qrAddress, qrPhone) have UpdatesPending = false. I check events OnAfterPost for details and only one was called, qrEmailAfterPost of course.
And next saPerson.ApplyUpdates and saPerson.CommitUpdates save only data for master and one detail.
Summary of my problem:
I insert record to master and also insert records to each of details. All of them have State = dsInsert. After Post on master, only master and one detail save inserted records into database. Two other details forgot inserted data.
Can you help me with this problem? Thanks

Why this code do not work in second time click button

I write this code for button click event . the first time I click the button every thing work correctly but when click for the second time on button it raise an error. whats the problem?
procedure TfrmMain.Button1Click(Sender: TObject);
var
B : Boolean;
begin
DM.tblTemp.DisableControls;
B:= DM.tblTemp.Locate('FoodName', DM.tblAsli.FieldByName('FoodName').AsString,[]) ;
if B then
begin
DM.tblTemp.Edit;
DM.tblTemp.FieldByName('Number').AsInteger:= DM.tblTemp.FieldByName('Number').AsInteger + 1;
DM.tblTemp.Post;
end
else
begin
DM.tblTemp.insert;
DM.tblTemp.FieldByName('FoodName').AsString := DM.tblAsli.FieldByName('FoodName').AsString;
DM.tblTemp.FieldByName('UnitPrice').AsInteger := DM.tblAsli.FieldByName('FoodPrice').AsInteger;
DM.tblTemp.FieldByName('Number').AsInteger := 1;
DM.tblTemp.Post;
end;
TotalPrice:= TotalPrice + DM.tblTemp.FieldByName('TotalPrice').AsInteger;
DM.tblTemp.EnableControls;
end;
the Error is
Row cannot be located for updating. Some values may have been changed
since it was last read
DM is data madual
tmbTbl is ADOTable
It is a pity you haven't said which DBMS you are using (e.g. Sql Server or MS Access,
nor told us a full list of the table's column types and indexes, if any.
The most likely answer to your q is that the variable B is set to False the first time
because the call to tblTemp.Locate fails to locate the Food name in question, so the Insert branch executes and the food's data is
added to the table but the second time the Edit branch executes and the error occurs,
though you have not said where, exactly. My guess would be on the call to .Post, because
the error message is one the ADO layer, which sits between the DBMS provider and your app,
emits when it attempts to post a change to the table but cannot identify which table row to update.
As I mentioned in a comment, the fix to this is usually at add a primary key index to the table, and I gather from your latest comment that this has succeeded for you. For the record and benefit of future readers it would be helpful if you could confirm which DBMS you are using and which Ole Driver you are using in your connection string.
Fwiw, I've tested your code using a table on MS Sql Server and MS Access and do not get the
error with either database.
Btw there is an obvious q, "How is it that tblTemp.Locate succeeds, but ADO is unable to
identify the correct record to post the update?" The answer is that tblTemp.Locate works in
a different way than identifying the relevant row to post the update.

How To Create Master Detail Report In Fast Report 4 + InstantObjects

How To Create Master Detail Report In Fast Report 4 + InstantObjects ? I can show report with master data but not with detail data. I'm Using FR 4, Delphi XE, and InstantObject.
Source code to display report :
frxDBDataset1.DataSet := (cxGridMaster.DataController.DataSource.DataSet);
frxDBDataset2.DataSet := (cxGridDetail.DataController.DataSource.DataSet);
frxReport1.DataSets.Add(DataModule1.frxDBDataset1); // Master Data
frxReport1.DataSets.Add(DataModule1.frxDBDataset2); // Detail
frxReport1.DesignReport;
Before inserting the detail dataSet in your report, define the property "MasterSource" of your detail dataSet as your master data name, too define the property "MasterField" and "IndexField" his with key field link between they.

Resources