Issue with delta values for reduced delta in case business rule triggered

I have an issue with the delta set that gets passed to the Update RO call

After a first ApplyUpdates which fails due to a server side business rule it looks like the fields are scrambled a bit

In my TProductDetailServerRules.BeforeProcessChange

I throw this exception raise OffDAUpdateException.Create(daerrormsg);

This gets handled on the client side via fBusinessRules.OnAfterMergeDelta

in which my code visualizes the issue in case delta’s still exist.

if Assigned (DataTable) and Assigned (DataTable.Delta) and
(DataTable.Delta.Count <> 0) then

If after this I do not reload (reset) the dataset and try ApplyUpdates again (but with one modified field so the business rule check passes)

The server throws an error which looks like the (old) delta values are totally mixed up

The 2 screenshots below is the delta info passed back to the client.

I notice a currency field prd_aankoopprijs is claimed to have old value ‘A’ (which is in fact probably just the value of another field)

Any idea what could cause this? How this can be prevented?

This is the code I use to visualize

Hi,

try to use NewValueByName[] instead of just NewValue[] as we do in BP:

          for i := 0 to (aDelta.LoggedFieldCount - 1) do begin
            remotename := aDelta.LoggedFieldNames[i];

..
            if lReducesDeltaMode and ROVariantsEqual(aChange.OldValueByName[remotename], aChange.NewValueByName[remotename]) and (lPKList.IndexOf(remotename) = -1) then Continue;
...
          end;

it may solve your issue with

Hi Evgeny,

It is not a visualization issue.

The server actually complains that the update cannot be performed.

For now due to a readonly field (but LogChanges still true) which he think has changed.

I’ll change the LogChanges property but I believe he will complain about other fields or incompatible types

FYI: After making the LogChanges adjustment no error occurs.

However I do not feel very confident that everything is OK.

I believe too many fields are set (cleared) in the DB

A change of one field results in

UPDATE Product SET “prd_DateChanged”= :prd_DateChanged, “prd_CNK”= :prd_CNK WHERE (“prd_PrimKey”=:OLD_prd_PrimKey) params: :prd_DateChanged=18/03/2026 10:56:12 :prd_CNK=0901057 :OLD_prd_PrimKey=100000643

After the bizrule trigger and correction it results in

UPDATE Product SET “prd_DateChanged”= :prd_DateChanged, “prd_UserId”= :prd_UserId, “prd_atc_primkey”= :prd_atc_primkey, “prd_atc_code”= :prd_atc_code, “prd_CNK”= :prd_CNK, “prd_Groothandelsproduct”= :prd_Groothandelsproduct,
“prd_DatumOpMarkt”= :prd_DatumOpMarkt, “prd_DatumSchrapping”= :prd_DatumSchrapping, “prd_CommercieleStatus”= :prd_CommercieleStatus, “prd_StatusWetgeving”= :prd_StatusWetgeving, “prd_CategorieAPB”= :prd_CategorieAPB,
“prd_CategorieOfficinall”= :prd_CategorieOfficinall, “prd_Gebruik”= :prd_Gebruik, “prd_Wetgeving”= :prd_Wetgeving, “prd_CodeDopingFrGem”= :prd_CodeDopingFrGem, “prd_CodeDopingVlGem”= :prd_CodeDopingVlGem,
“prd_ptv_primkey”= :prd_ptv_primkey, “prd_Bereiding”= :prd_Bereiding, “prd_Bewaartemperatuur”= :prd_Bewaartemperatuur, “prd_HeeftBarcode”= :prd_HeeftBarcode, “prd_LabelAPB”= :prd_LabelAPB, “prd_Steriel”= :prd_Steriel,
“prd_CodeVerdovingsmiddel”= :prd_CodeVerdovingsmiddel, “prd_Hospitaalverpakking”= :prd_Hospitaalverpakking, “prd_EnkelTBTInHospitaal”= :prd_EnkelTBTInHospitaal, “prd_IsVoorschriftPlichtig”= :prd_IsVoorschriftPlichtig,
“prd_IsImport”= :prd_IsImport, “prd_IsVerdoving”= :prd_IsVerdoving, “prd_IsVeterinair”= :prd_IsVeterinair, “prd_CodeUnidosis”= :prd_CodeUnidosis, “prd_Originaliteit”= :prd_Originaliteit,
“prd_HoeveelheidPerVerpakking”= :prd_HoeveelheidPerVerpakking, “prd_AantalIEInsulPerVerpakking”= :prd_AantalIEInsulPerVerpakking, “prd_GeldigheidsdatumPrijsInfo”= :prd_GeldigheidsdatumPrijsInfo,
“prd_EigenAankoopPrijs”= :prd_EigenAankoopPrijs, “prd_Publieksprijs”= :prd_Publieksprijs, “prd_VorigePublieksprijs”= :prd_VorigePublieksprijs, “prd_EigenPrijs”= :prd_EigenPrijs, “prd_Richtprijs”= :prd_Richtprijs,
“prd_BTWCode”= :prd_BTWCode, “prd_IsTBTHomeopathie”= :prd_IsTBTHomeopathie, “prd_Terugbetalingsbasis”= :prd_Terugbetalingsbasis, “prd_CodeFiscaalForfait”= :prd_CodeFiscaalForfait, “prd_IBCode”= :prd_IBCode,
“prd_MinVoorraad”= :prd_MinVoorraad, “prd_MaxVoorraad”= :prd_MaxVoorraad, “prd_AantalTeBestellen”= :prd_AantalTeBestellen, “prd_AutomatischBestellen”= :prd_AutomatischBestellen, “prd_sbs_Primkey”= :prd_sbs_Primkey,
“prd_sbs_Status”= :prd_sbs_Status, “prd_sbs_LaatstGetriggerd”= :prd_sbs_LaatstGetriggerd, “prd_lev_Primkey”= :prd_lev_Primkey, “prd_korting”= :prd_korting, “prd_lok_Primkey”= :prd_lok_Primkey,
“prd_Geldigheidsdatum”= :prd_Geldigheidsdatum, “prd_pgs_primkey”= :prd_pgs_primkey, “prd_pga_primkey”= :prd_pga_primkey, “prd_Dynaphar”= :prd_Dynaphar, “prd_IsSchriftelijkeAanvraag”= :prd_IsSchriftelijkeAanvraag,
“prd_Hernieuwing”= :prd_Hernieuwing, “prd_HernieuwingCyclisch”= :prd_HernieuwingCyclisch, “prd_HernieuwingMaanden”= :prd_HernieuwingMaanden, “prd_HernieuwingAantal”= :prd_HernieuwingAantal,
“prd_IsGeneriek”= :prd_IsGeneriek, “prd_HeeftAstmatomInfo”= :prd_HeeftAstmatomInfo, “prd_HeeftEersteAflevering”= :prd_HeeftEersteAflevering, “prd_IsJongereProduct”= :prd_IsJongereProduct, “prd_DPP”= :prd_DPP,
“prd_DDD”= :prd_DDD, “prd_ehd_DDD”= :prd_ehd_DDD, “prd_inhoud”= :prd_inhoud, “prd_ehd_Inhoud”= :prd_ehd_Inhoud, “prd_HeeftUniekeBarcode”= :prd_HeeftUniekeBarcode, “prd_RefNR”= :prd_RefNR,
“prd_HeeftVervalDatum”= :prd_HeeftVervalDatum, “prd_vervaldatum”= :prd_vervaldatum, “prd_IsGeneesmiddel”= :prd_IsGeneesmiddel, “prd_TransmissieTD”= :prd_TransmissieTD, “prd_PrintBVAC”= :prd_PrintBVAC,
“prd_IsCompendium”= :prd_IsCompendium, “prd_NietMagistraal”= :prd_NietMagistraal, “prd_ZorgTrajecten”= :prd_ZorgTrajecten, “prd_IsDelphiCare”= :prd_IsDelphiCare, “prd_IsCybele”= :prd_IsCybele,
“prd_IsBCFI”= :prd_IsBCFI, “prd_IsPharmaGuide”= :prd_IsPharmaGuide, “prd_RizivTerugbetaalbaar”= :prd_RizivTerugbetaalbaar, “prd_HeeftReferentieTBT”= :prd_HeeftReferentieTBT, “prd_BasisHono”= :prd_BasisHono,
“prd_AfFabriekPrijs”= :prd_AfFabriekPrijs, “prd_AfFabriekTBBasis”= :prd_AfFabriekTBBasis, “prd_TerugNameStatus”= :prd_TerugNameStatus, “prd_TerugNameVoorVerval”= :prd_TerugNameVoorVerval,
“prd_TerugNameNaVerval”= :prd_TerugNameNaVerval, “prd_IsLeverbaar”= :prd_IsLeverbaar, “prd_blisterrobotafvulbaar”= :prd_blisterrobotafvulbaar, “prd_DoMycarenet”= :prd_DoMycarenet, “prd_InTar31”= :prd_InTar31,
“prd_PrijsIndicator”= :prd_PrijsIndicator, “prd_NietVSVroedVrouw”= :prd_NietVSVroedVrouw, “prd_BNM”= :prd_BNM, “prd_inTar43”= :prd_inTar43, “prd_QLev_Primkey”= :prd_QLev_Primkey, “prd_QMax”= :prd_QMax,
“prd_QMin”= :prd_QMin, “prd_UseQ”= :prd_UseQ WHERE (“prd_PrimKey”=:OLD_prd_PrimKey) params: :prd_DateChanged=18/03/2026 10:51:54 :prd_UserId=8 :prd_atc_primkey=0 :prd_atc_code= :prd_CNK=0901059
:prd_Groothandelsproduct=False :prd_DatumOpMarkt=0:00:00 :prd_DatumSchrapping=0:00:00 :prd_CommercieleStatus= :prd_StatusWetgeving= :prd_CategorieAPB= :prd_CategorieOfficinall= :prd_Gebruik= :prd_Wetgeving=
:prd_CodeDopingFrGem= :prd_CodeDopingVlGem= :prd_ptv_primkey=900 :prd_Bereiding= :prd_Bewaartemperatuur= :prd_HeeftBarcode=True :prd_LabelAPB=False :prd_Steriel=False :prd_CodeVerdovingsmiddel=
:prd_Hospitaalverpakking=False :prd_EnkelTBTInHospitaal=False :prd_IsVoorschriftPlichtig=False :prd_IsImport=False :prd_IsVerdoving=False :prd_IsVeterinair=False :prd_CodeUnidosis= :prd_Originaliteit=
:prd_HoeveelheidPerVerpakking=0 :prd_AantalIEInsulPerVerpakking=0 :prd_GeldigheidsdatumPrijsInfo=0:00:00 :prd_EigenAankoopPrijs=0 :prd_Publieksprijs=0 :prd_VorigePublieksprijs=0 :prd_EigenPrijs=0
:prd_Richtprijs=False :prd_BTWCode=1 :prd_IsTBTHomeopathie=False :prd_Terugbetalingsbasis=0 :prd_CodeFiscaalForfait= :prd_IBCode= :prd_MinVoorraad=0 :prd_MaxVoorraad=0 :prd_AantalTeBestellen=0
:prd_AutomatischBestellen=False :prd_sbs_Primkey=0 :prd_sbs_Status=0 :prd_sbs_LaatstGetriggerd=0:00:00 :prd_lev_Primkey=0 :prd_korting=0 :prd_lok_Primkey=0 :prd_Geldigheidsdatum=0:00:00 :prd_pgs_primkey=0
:prd_pga_primkey=0 :prd_Dynaphar=False :prd_IsSchriftelijkeAanvraag=False :prd_Hernieuwing=False :prd_HernieuwingCyclisch=False :prd_HernieuwingMaanden=0 :prd_HernieuwingAantal=0 :prd_IsGeneriek=False
:prd_HeeftAstmatomInfo=False :prd_HeeftEersteAflevering=False :prd_IsJongereProduct=False :prd_DPP=0 :prd_DDD=0 :prd_ehd_DDD=0 :prd_inhoud=0 :prd_ehd_Inhoud=0 :prd_HeeftUniekeBarcode=False
:prd_RefNR= :prd_HeeftVervalDatum=True :prd_vervaldatum=3/10/2013 :prd_IsGeneesmiddel=False :prd_TransmissieTD=False :prd_PrintBVAC=False :prd_IsCompendium=False :prd_NietMagistraal=False
:prd_ZorgTrajecten= :prd_IsDelphiCare=False :prd_IsCybele=False :prd_IsBCFI=False :prd_IsPharmaGuide=False :prd_RizivTerugbetaalbaar=False :prd_HeeftReferentieTBT=False :prd_BasisHono=False
:prd_AfFabriekPrijs=0 :prd_AfFabriekTBBasis=0 :prd_TerugNameStatus=9 :prd_TerugNameVoorVerval=0 :prd_TerugNameNaVerval=0 :prd_IsLeverbaar=0 :prd_blisterrobotafvulbaar=False :prd_DoMycarenet=False
:prd_InTar31=False :prd_PrijsIndicator=0 :prd_NietVSVroedVrouw=False :prd_BNM=False :prd_inTar43=False :prd_QLev_Primkey=0 :prd_QMax=0 :prd_QMin=0 :prd_UseQ=False :OLD_prd_PrimKey=100000643

Hi,

for ReducedDelta = true, you have a big SQL unless those fields were changed.
Can you log actual delta change?

I don’t understand your comment or suggestion.

This is a big issue. How can we proceed? Maybe we can have a call and I show you the issue?

Hi,

Can you show client-side request that contains delta, i.e. stream that send to server for UpdateData method ?

You can drop email to support@ and attach that file for keeping privacy.

Not sure what you want me to send.

2x binary content serializeddata? First call & second call?

FYI: Client side we call via a custom RO function ‘UpdateProduct’

Our dataobject TProductDetailDATable is derived from TDAMemDataTable.

Server side: Multiple deltas get processed (see function below)

but the issue is related to the master table ProductDetail

The issue is raised inside

BizProcessor.ProcessDelta(Connection, Delta, [ctDelete, ctInsert, ctUpdate]);

function TOffServerService.UpdateProduct(const Delta: Binary): Binary;
var
  InfoDelta, ProductDelta, ProductLeverancierDelta, ProductTarificatieDelta, ProductNaamDelta, ProductStockDelta, ProductChemieLinkDelta, ProductSynoniemDelta, ProductWetenSchappelijkDelta,
    ProductEANDelta: IDADelta;
begin // FVC 02/2025: The Delta binary only contains Product DA schema - code does nothing really
  try
    try
      Connection.BeginTransaction();
      // Initializing
      DABINDataStreamer.Initialize(Delta, aiRead);
      Try
        // Unpacking…
        // WDV (9/01/2004 11:14:23) Opgelet: we moeten alle mogelijke deltas
        // WDV (9/01/2004 11:14:31) gaan benaderen, anders krijgen we problemen
        ProductDelta := ReadDeltaIfExist(DABINDataStreamer, 'ProductDetail');
        ProductLeverancierDelta := ReadDeltaIfExist(DABINDataStreamer, 'ProductLeverancier');
        ProductNaamDelta := ReadDeltaIfExist(DABINDataStreamer, 'ProductNaam');
        ProductStockDelta := ReadDeltaIfExist(DABINDataStreamer, 'ProductStock');
        InfoDelta := ReadDeltaIfExist(DABINDataStreamer, 'Info');
        ProductChemieLinkDelta := ReadDeltaIfExist(DABINDataStreamer, 'ProductLinkChemie');
        ProductSynoniemDelta := ReadDeltaIfExist(DABINDataStreamer, 'ProductSynoniem');
        ProductWetenSchappelijkDelta := ReadDeltaIfExist(DABINDataStreamer, 'ProductWetenSchappelijk');
        ProductEANDelta := ReadDeltaIfExist(DABINDataStreamer, 'ProductEAN');
        ProductTarificatieDelta := ReadDeltaIfExist(DABINDataStreamer, 'ProductTarifikatie');
      Finally
        DABINDataStreamer.Finalize;
      End;

      if (ProductChemieLinkDelta <> nil) then
        ChmLinkPrdProcessor.ProcessDelta(Connection, ProductChemieLinkDelta, [ctDelete, ctInsert, ctUpdate]);
      if (ProductSynoniemDelta <> nil) then
        ProductSynoniemProcessor.ProcessDelta(Connection, ProductSynoniemDelta, [ctDelete, ctInsert, ctUpdate]);
      if (ProductWetenSchappelijkDelta <> nil) then
        ProductWetenschappelijkProcessor.ProcessDelta(Connection, ProductWetenSchappelijkDelta, [ctDelete, ctInsert, ctUpdate]);
      if (ProductEANDelta <> nil) then
        ProductEANProcessor.ProcessDelta(Connection, ProductEANDelta, [ctDelete, ctInsert, ctUpdate]);
      if (ProductLeverancierDelta <> nil) then
        PlvProcessor.ProcessDelta(Connection, ProductLeverancierDelta, [ctDelete, ctInsert, ctUpdate]);

      CheckProcessDelta(Connection, ProductNaamProcessor, ProductNaamDelta, nil);
      if (InfoDelta <> nil) then
        InfoProcessor.ProcessDelta(Connection, InfoDelta, [ctDelete, ctInsert, ctUpdate]);
      // we doen niets met tarificatie delta

      // if (ProductTarificatieDelta <> nil) then
      // ProductTarificatieProcessor.ProcessDelta(Connection,
      // ProductTarificatieDelta,[ctDelete, ctInsert, ctUpdate]);
      if (ProductStockDelta <> nil) then
        ProductStockProcessor.ProcessDelta(Connection, ProductStockDelta, [ctDelete, ctInsert, ctUpdate]);
      CheckProcessDelta(Connection, ProductDetailProcessor, ProductDelta, Delta);

      Connection.CommitTransaction();
    except
      Connection.RollbackTransaction();
      raise;
    end;

  finally
    Result := Binary.Create();

    DABINDataStreamer.Initialize(Result, aiWrite);
    try
      if Assigned(ProductDelta) then
        DABINDataStreamer.WriteDelta(ProductDelta);
      if Assigned(ProductLeverancierDelta) then
        DABINDataStreamer.WriteDelta(ProductLeverancierDelta);
      if Assigned(ProductNaamDelta) then
        DABINDataStreamer.WriteDelta(ProductNaamDelta);
      if Assigned(ProductTarificatieDelta) then
        DABINDataStreamer.WriteDelta(ProductTarificatieDelta);
      if Assigned(InfoDelta) then
        DABINDataStreamer.WriteDelta(InfoDelta);
      if Assigned(ProductStockDelta) then
        DABINDataStreamer.WriteDelta(ProductStockDelta);
      if Assigned(ProductWetenSchappelijkDelta) then
        DABINDataStreamer.WriteDelta(ProductWetenSchappelijkDelta);
      if Assigned(ProductEANDelta) then
        DABINDataStreamer.WriteDelta(ProductEANDelta);
      if Assigned(ProductSynoniemDelta) then
        DABINDataStreamer.WriteDelta(ProductSynoniemDelta);
      if Assigned(ProductChemieLinkDelta) then
        DABINDataStreamer.WriteDelta(ProductChemieLinkDelta);
    finally
      DABINDataStreamer.Finalize();
    end;

  end;
end;

function CheckProcessDelta(Connection: IDAConnection; BizProcessor: TDABusinessProcessor; Delta: IDADelta; BinDelta: Binary): boolean;
begin
  Result := True;
  if (Delta <> nil) then
    BizProcessor.ProcessDelta(Connection, Delta, [ctDelete, ctInsert, ctUpdate]);
  if (BinDelta <> nil) then
    CheckPropagateUpdateToCloud(Delta.LogicalName, BinDelta);
end;

By the way I noticed that Delta.Size=3220 for the first call and it is 2994 for the second call

Delta of my server side

image

FYI: This is what raises the error server side. A raise Exception inside BeforeProcessChange

Hi,

lets detect firstly why you have A in currency field.
is it possible to create a very simple testcase that reproduces this case?
will whole things work if you are using standard UpdateData instead of customUpdateProduct method?

note: std UpdateData works correctly with m/d tables.