Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    No cache synchronization with additional criteria in update

    SmartClient Version: v13.0p_2025-02-01/Enterprise Deployment (built 2025-02-01)

    Hi, I'm noticing a change in behaviour with the latest 13.0 in a server-side update that uses additional criteria beyond the primary key. Previously, the log was:

    Code:
    2025-02-12T15:52:27,378 INFO DSRequest Executing JTK_ACC_UTENTI.update with
    criteria: {
        _constructor:"AdvancedCriteria",
        criteria:[
            {fieldName:"ID_REC", value:9866637, operator:"equals"},
            {
                criteria:[
                    {
                        criteria:[
                            {
                                criteria:[
                                    {fieldName:"UTENTE_ASSEGNATO", operator:"isNull"},
                                    {fieldName:"FL_APPROVATO", operator:"isNull"}
                                ],
                                operator:"and"
                            },
                            {
                                criteria:[
                                    {fieldName:"UTENTE_ASSEGNATO", operator:"isNull"},
                                    {fieldName:"FL_APPROVATO", value:"Y", operator:"equals"}
                                ],
                                operator:"and"
                            }
                        ],
                        operator:"or"
                    }
                ],
                operator:"and"
            }
        ],
        __normalized:true,
        operator:"and"
    }
    values: {FL_APPROVATO:"V", DATA_PRESA_IN_CARICO:new Date(1739371933863)}
    2025-02-12T15:52:27,452 DEBUG AppBase No userTypes defined, allowing anyone access to all operations for this application
    2025-02-12T15:52:27,453 DEBUG AppBase No public zero-argument method named '_null' found, performing generic datasource operation
    2025-02-12T15:52:27,584 DEBUG SQLDataSource In getSchemaName(); for DataSource JTK_ACC_UTENTI
    2025-02-12T15:52:27,584 DEBUG SQLDataSource 'schema' retrieved from config is 'DBSALES'
    2025-02-12T15:52:27,608 DEBUG SQLDataSource Setting DSRequest as being part of a transaction on connection 1388489570
    2025-02-12T15:52:27,608 INFO SQL Executing SQL query on 'dbJpcEP': UPDATE DBSALES.JTK_ACC_UTENTI SET DATA_PRESA_IN_CARICO=TO_DATE('2025-02-12 15:52:13','YYYY-MM-DD HH24:MI:SS'), FL_APPROVATO='V', MODIFIER='foo@bar.it', MODIFIER_TIMESTAMP=TO_DATE('2025-02-12 15:52:27','YYYY-MM-DD HH24:MI:SS') WHERE ((JTK_ACC_UTENTI.ID_REC = 9866637 AND JTK_ACC_UTENTI.ID_REC IS NOT NULL) AND ((((JTK_ACC_UTENTI.UTENTE_ASSEGNATO IS NULL) AND (JTK_ACC_UTENTI.FL_APPROVATO IS NULL)) OR ((JTK_ACC_UTENTI.UTENTE_ASSEGNATO IS NULL) AND (JTK_ACC_UTENTI.FL_APPROVATO = 'Y' AND JTK_ACC_UTENTI.FL_APPROVATO IS NOT NULL)))))
    2025-02-12T15:52:27,761 DEBUG SQLDataSource update operation affected 1 rows
    2025-02-12T15:52:27,763 INFO DSRequest primaryKeys: {ID_REC=9866637}
    2025-02-12T15:52:27,769 DEBUG SQLDataSource In getSchemaName(); for DataSource JTK_ACC_UTENTI
    2025-02-12T15:52:27,769 DEBUG SQLDataSource 'schema' retrieved from config is 'DBSALES'
    2025-02-12T15:52:27,780 INFO DSRequest Executing JTK_ACC_UTENTI.fetch rows: 0->-1 with
    criteria: {ID_REC:9866637}
    2025-02-12T15:52:27,894 DEBUG AppBase No userTypes defined, allowing anyone access to all operations for this application
    2025-02-12T15:52:27,895 DEBUG AppBase No public zero-argument method named '_null' found, performing generic datasource operation
    2025-02-12T15:52:27,920 DEBUG SQLDataSource DataSource 1104 acquired SQLDriver instance 2018581637 during initialization
    2025-02-12T15:52:27,931 DEBUG SQLDataSource DataSource 1105 acquired SQLDriver instance 510386460 during initialization
    2025-02-12T15:52:27,941 DEBUG SQLDataSource DataSource 1107 acquired SQLDriver instance 142246600 during initialization
    2025-02-12T15:52:27,952 DEBUG SQLDataSource DataSource 1109 acquired SQLDriver instance 436189416 during initialization
    2025-02-12T15:52:27,954 DEBUG SQLDataSource In getSchemaName(); for DataSource JTK_ACC_UTENTI
    2025-02-12T15:52:27,954 DEBUG SQLDataSource 'schema' retrieved from config is 'DBSALES'
    2025-02-12T15:52:27,955 DEBUG SQLDataSource In getSchemaName(); for DataSource JPC_NAZIONI
    2025-02-12T15:52:27,955 DEBUG SQLDataSource 'schema' retrieved from config is 'DBSALES'
    2025-02-12T15:52:27,955 DEBUG SQLDataSource In getSchemaName(); for DataSource JPC_PROVINCE
    2025-02-12T15:52:27,955 DEBUG SQLDataSource 'schema' retrieved from config is 'DBSALES'
    2025-02-12T15:52:27,955 DEBUG SQLDataSource In getSchemaName(); for DataSource JPC_COMUNI
    2025-02-12T15:52:27,956 DEBUG SQLDataSource 'schema' retrieved from config is 'DBSALES'
    2025-02-12T15:52:27,956 DEBUG SQLDataSource In getSchemaName(); for DataSource JTK_ACC_TIPI_UTENTI
    2025-02-12T15:52:27,956 DEBUG SQLDataSource 'schema' retrieved from config is 'DBSALES'
    2025-02-12T15:52:27,970 DEBUG SQLDataSource DataSource 1103 acquired SQLDriver instance 1765419622 during initialization
    2025-02-12T15:52:27,989 DEBUG SQLDataSource JDBC driver windowed select rows 0->-1, result size 1. Query: SELECT JTK_ACC_UTENTI.ID_REC, JTK_ACC_UTENTI.ID_REC_IMP, JTK_ACC_UTENTI.ALLEGATO_FILENAME, JTK_ACC_UTENTI.ALLEGATO_FILESIZE, JTK_ACC_UTENTI.ALLEGATO_DATE_CREATED, JTK_ACC_UTENTI.ALLEGATO_FILETYPE, JTK_ACC_UTENTI.ALL_PAG_PRIVACY_FILENAME, JTK_ACC_UTENTI.ALL_PAG_PRIVACY_FILESIZE, JTK_ACC_UTENTI.ALL_PAG_PRIVACY_DATE_CREATED, JTK_ACC_UTENTI.ALL_PAG_PRIVACY_FILETYPE, JTK_ACC_UTENTI.COGNOME, JTK_ACC_UTENTI.NOME, JTK_ACC_UTENTI.COGNOME_REF, JTK_ACC_UTENTI.NOME_REF, JTK_ACC_UTENTI.DESC_SPONSOR, JTK_ACC_UTENTI.DOMINO_UNID, JTK_ACC_UTENTI.EMAIL, JTK_ACC_UTENTI.EMAIL_REF, JTK_ACC_UTENTI.NUMERO_PRATICA, JTK_ACC_UTENTI.NUMERO_TESSERA, JTK_ACC_UTENTI.PASSWORD, JTK_ACC_UTENTI.TELEFONO, JTK_ACC_UTENTI.TIPO_CERTIFICATO, JTK_ACC_UTENTI.TIPO_TESSERA, JTK_ACC_UTENTI.DATA_NASCITA, JTK_ACC_UTENTI.DATA_TESSERA, JTK_ACC_UTENTI.SCADENZA_TESSERA, JTK_ACC_UTENTI.FL_APPROVATO, JTK_ACC_UTENTI.IS_DEAMBULANTE, JTK_ACC_UTENTI.IS_INVALIDITA_TOTALE, JTK_ACC_UTENTI.IS_PRIMO_LOGIN, JTK_ACC_UTENTI.IS_PRATICHE_ALLEGATE, JTK_ACC_UTENTI.ID_COMUNE_NASCITA_FK, JTK_ACC_UTENTI.ID_NAZIONE_NASCITA_FK, JTK_ACC_UTENTI.ID_PROVINCIA_NASCITA_FK, JTK_ACC_UTENTI.ID_TIPO_UTENTE_FK, (CASE JTK_ACC_TIPI_UTENTI.CODICE WHEN '1' THEN 'disabili' WHEN '2' THEN 'tesserati' WHEN '3' THEN 'sponsor' END) AS URL_FOR_MAIL_PARAMETER, JTK_ACC_UTENTI.DOC_URL, JTK_ACC_UTENTI.IMP_FILENAME, JTK_ACC_UTENTI.FL_IMPORTED, JTK_ACC_UTENTI.DATA_CREAZIONE_DOM, JTK_ACC_UTENTI.NOME || ' ' || JTK_ACC_UTENTI.COGNOME AS DENOMINAZIONE, JTK_ACC_UTENTI.TK_IDENT, JTK_ACC_UTENTI.FL_SND_GDPR, JTK_ACC_UTENTI.FL_SND_GDPR_REMIND, JTK_ACC_UTENTI.FL_PRV_TERMINI, JTK_ACC_UTENTI.FL_PRV_SALUTE, JTK_ACC_UTENTI.FL_PRV_MRKT, JTK_ACC_UTENTI.FL_DATI_CONF, JTK_ACC_UTENTI.IS_LOGIC_DEL, JTK_ACC_UTENTI.CODICE_UNIVOCO, JTK_ACC_UTENTI.JUVENTUS_CARD, JTK_ACC_UTENTI.SETTORE, JTK_ACC_UTENTI.FILA, JTK_ACC_UTENTI.POSTO, JTK_ACC_UTENTI.IS_RINNOVO, JTK_ACC_UTENTI.CREATOR_TIMESTAMP, JTK_ACC_UTENTI.MODIFIER_TIMESTAMP, JTK_ACC_UTENTI.CREATOR, JTK_ACC_UTENTI.MODIFIER, JTK_ACC_UTENTI.LOTTO_ESTRAZIONE_CU, JTK_ACC_UTENTI.LOTTO_ESTRAZIONE_JC, JTK_ACC_UTENTI.UTENTE_ASSEGNATO, JTK_ACC_UTENTI.DATA_PRESA_IN_CARICO, JTK_ACC_UTENTI.ID_PROVINCIA_RESIDENZA_FK, JTK_ACC_UTENTI.ID_COMUNE_RESIDENZA_FK, JTK_ACC_UTENTI.ID_NAZIONE_RESIDENZA_FK, JTK_ACC_UTENTI.TOKEN_RESET_PSW, JTK_ACC_UTENTI.TIMESTAMP_TOKEN_RESET_PSW, JTK_ACC_UTENTI.FL_CONF_OVER_16, JTK_ACC_UTENTI.FL_CONF_UNDER_16_PAR, JTK_ACC_UTENTI.IS_NUOVO_ABBONATO, JTK_ACC_UTENTI.FL_MAIL_CLUSTER_II, JTK_ACC_UTENTI.IS_PREVISTA_REVISIONE, JTK_ACC_UTENTI.DATA_PREVISTA_REVISIONE, JTK_ACC_UTENTI.HAS_CORREZIONE_UNDER_OVER_18, JTK_ACC_UTENTI.GENERE, JTK_ACC_TIPI_UTENTI.CODICE AS CODICE_TIPO_UTENTE, nazione_nascita.NOME AS NAZIONE_NASCITA, provincia_nascita.NOME AS PROVINCIA_NASCITA, comune_nascita.NOME AS COMUNE_NASCITA FROM DBSALES.JTK_ACC_UTENTI, DBSALES.JPC_NAZIONI nazione_nascita, DBSALES.JPC_PROVINCE provincia_nascita, DBSALES.JPC_COMUNI comune_nascita, DBSALES.JTK_ACC_TIPI_UTENTI WHERE (JTK_ACC_UTENTI.ID_REC=9866637) AND JTK_ACC_UTENTI.ID_TIPO_UTENTE_FK = JTK_ACC_TIPI_UTENTI.ID_REC AND JTK_ACC_UTENTI.ID_NAZIONE_NASCITA_FK = nazione_nascita.ID_REC(+) AND JTK_ACC_UTENTI.ID_PROVINCIA_NASCITA_FK = provincia_nascita.ID_REC(+) AND JTK_ACC_UTENTI.ID_COMUNE_NASCITA_FK = comune_nascita.ID_REC(+)
    2025-02-12T15:52:27,990 DEBUG SQLDataSource Setting DSRequest as being part of a transaction on connection 1388489570
    2025-02-12T15:52:28,094 DEBUG SQLDataSource Using paging strategy 'jdbcScroll' - scrolling to absolute position 1
    2025-02-12T15:52:28,094 DEBUG SQLDataSource Scrolling / positioning took 0ms
    2025-02-12T15:52:28,113 INFO DSResponse DSResponse: List with 1 items
    2025-02-12T15:52:28,118 INFO DSResponse DSResponse: List with 1 items
    Now the log is:

    Code:
    2025-02-12T14:25:26,314 INFO DSRequest Executing JTK_ACC_UTENTI.update with
    criteria: {
        _constructor:"AdvancedCriteria",
        criteria:[
            {fieldName:"ID_REC", value:9866637, operator:"equals"},
            {
                criteria:[
                    {
                        criteria:[
                            {
                                criteria:[
                                    {fieldName:"UTENTE_ASSEGNATO", operator:"isNull"},
                                    {fieldName:"FL_APPROVATO", operator:"isNull"}
                                ],
                                operator:"and"
                            },
                            {
                                criteria:[
                                    {fieldName:"UTENTE_ASSEGNATO", operator:"isNull"},
                                    {fieldName:"FL_APPROVATO", value:"Y", operator:"equals"}
                                ],
                                operator:"and"
                            }
                        ],
                        operator:"or"
                    }
                ],
                operator:"and"
            }
        ],
        __normalized:true,
        operator:"and"
    }
    values: {FL_APPROVATO:"V", DATA_PRESA_IN_CARICO:new Date(1739366719592)}
    2025-02-12T14:25:26,354 DEBUG AppBase No userTypes defined, allowing anyone access to all operations for this application
    2025-02-12T14:25:26,355 DEBUG AppBase No public zero-argument method named '_null' found, performing generic datasource operation
    2025-02-12T14:25:26,389 DEBUG SQLDataSource In getSchemaName(); for DataSource JTK_ACC_UTENTI
    2025-02-12T14:25:26,389 DEBUG SQLDataSource 'schema' retrieved from config is 'DBSALES'
    2025-02-12T14:25:26,413 DEBUG SQLDataSource Setting DSRequest as being part of a transaction on connection 1379797401
    2025-02-12T14:25:26,413 INFO SQL Executing SQL query on 'dbJpcEP': UPDATE DBSALES.JTK_ACC_UTENTI SET DATA_PRESA_IN_CARICO=TO_DATE('2025-02-12 14:25:19','YYYY-MM-DD HH24:MI:SS'), FL_APPROVATO='V', MODIFIER='foo@bar.it', MODIFIER_TIMESTAMP=TO_DATE('2025-02-12 14:25:26','YYYY-MM-DD HH24:MI:SS') WHERE ((JTK_ACC_UTENTI.ID_REC = 9866637 AND JTK_ACC_UTENTI.ID_REC IS NOT NULL) AND ((((JTK_ACC_UTENTI.UTENTE_ASSEGNATO IS NULL) AND (JTK_ACC_UTENTI.FL_APPROVATO IS NULL)) OR ((JTK_ACC_UTENTI.UTENTE_ASSEGNATO IS NULL) AND (JTK_ACC_UTENTI.FL_APPROVATO = 'Y' AND JTK_ACC_UTENTI.FL_APPROVATO IS NOT NULL)))))
    2025-02-12T14:25:26,501 INFO DSRequest This update request on dataSource 'JTK_ACC_UTENTI' is for operationBinding 'null', which is marked allowMultiUpdate: true. No cache synchronization will be run.
    2025-02-12T14:25:26,505 DEBUG SQLDataSource cache sync skipped by dsRequest.setSkipCacheSync() directive - setting invalidateCache: true on response
    2025-02-12T14:25:26,505 DEBUG SQLDataSource update operation affected 1 rows
    2025-02-12T14:25:26,507 DEBUG SQLDataSource cache sync skipped by dsRequest.setSkipCacheSync() directive - setting invalidateCache: true on response
    As you can see, the log now says: "...which is marked allowMultiUpdate: true. No cache synchronization will be run."

    Could it be related to this fix https://forums.smartclient.com/forum...ate#post274725 ?


    #2
    Additional criteria beyond a PK cannot do anything since the PK is already unique. Perhaps the PK is faked here (not really unique) and you set allowMultiUpdate to hack around this? Because it’s correct for allowMultiUpdate to not attempt cache sync.

    Comment


      #3
      Hello, I believe there has been a change in behaviour that unfortunately breaks my code.

      First, I'd like to confirm something.

      I noticed that the documentation states:
      "Note, in the case of doing an update or delete operation with a primary key and additional criteria, allowMultiUpdate must be set or additional criteria will be dropped and just the primary key fields will be used in criteria."
      starting from version 12.1 onward. However, this only applies to DSRequests constructed on the server side. That is, if an update comes from the client and I add criteria in a DMI, those criteria are always retained. Is that correct?

      Now, going back to the logs from my first post, which were generated by my (rather old) piece of code: in those logs, allowMultiUpdate=true is not set. However, if I use version 13.0-p20240810 (which produces the first log) and call dsRequest.getAllowMultiUpdate(), it returns false, whereas in the latest 13.0 version (which produces the second log), it returns true, and indeed, the extra criteria are not removed.

      I have now discovered that this happens because the DSRequest is constructed without an RPCManager, but with a DSTransaction: if I create it with an RPCManager instead, then the extra criteria are ignored. Is it a bug?

      As for why I have server-side code adding these criteria: as far as I remember, it's to avoid updating a record that someone else has already updated before me, or maybe to avoid someone updating a record which he shouldn't update.

      Would it be possible to have a flag to allow this behaviour (and without enabling allowMultiUpdate)? Essentially, to have it behave as the dsRequest is a client request.

      Comment


        #4
        OK, multiple things to clarify here:

        1. we can't really figure out what you mean about dsRequest.getAllowMultiUpdate() returning false - it's not clear if it's correctly returning false (because you didn't set the property) or not, but it also sounds like it's behaving as expected, so let us know if you are reporting something as wrong here

        2. client-side "update" requests indeed limit criteria to the primary key, but this behavior is very old, not from 12.1. There was, however, a documentation clarification which was added to 12.1 and prior versions (with no behavior change).

        3. server-created requests do allow additional criteria (with or without allowMultiUpdate=true)

        4. providing an RPCManager to a DSRequest causes it to be treated like a client-side request, that is, it is subject to the same security restrictions as client requests. This includes having additional criteria, and this is as documented and as designed. You can, however, override this (dsRequest.setClientRequest(false))

        5. It sounds like you are hoping for extra criteria from the client to be allowed, but you don't want to have to set allowMultiUpdate: true, since aside from that being dangerous, it also turns off cache sync. Is the correct?

        As far as how to handle this, with the existing system, you could either:

        1. setClientRequest(false) to remove security constraints - but keep in mind this removes all security constraints. For example, the request might omit the PK and a mass update / mass delete would be allowed

        2. just perform cache sync yourself, which is nearly a one-liner, roughly: return new DSRequest("fetch", [provide the PK as criteria]).execute()

        We could possibly just add an additional flag, something like allowExtraCriteria, which allows client-submitted requests to apply additional criteria. However this is a fairly substantial task, so we would only tackle it via Feature Sponsorship.

        Comment


          #5
          Hello, for now let's stick to the problem from the first post. It's a server-side DSRequest, ie in a DMI I've got code like:

          Code:
                  DSRequest dsRequest = new DSRequest("JTK_ACC_UTENTI", DataSource.OP_UPDATE);
                  dsRequest.setDSTransaction( dsTransaction);
                  dsRequest.setCriteria(criteria);  // criteria with pk and additional criteria
                  dsRequest.setValues(values);
                  DSResponse dsResponse = dsRequest.execute();
          and allowMultiUpdate is not set.

          Code like this, in 12.1 was generating an update which contains all criteria in the where clause, and was also returning the updated record in the dsResponse.

          It was also behaving like that in v13.0p_2024-08-10/Enterprise Deployment, but in the latest 13.0, after the update with additional criteria, it's logging:
          Code:
          DSRequest This update request on dataSource 'JTK_ACC_UTENTI' is for operationBinding 'null', which is marked allowMultiUpdate: true. No cache synchronization will be run.
          So the dsResponse doesn't contain the updated record. It isn't easy for me to catch all the places in my code where I could possibly have this issue.


          PS: about the other points, I think it'd be better if I start some new threads.
          Last edited by claudiobosticco; 19 Feb 2025, 14:39.

          Comment


            #6
            We have today committed a fix for this change in behavior, on all branches from 13.0 upwards. The fix should be in as of tomorrow's builds, dated February 21st or later. Please check and confirm that your use case now works as expected.

            Comment

            Working...
            X