Loading
Procedure consigliate per gli hook prezzi Apex

Procedure consigliate per gli hook prezzi Apex

Seguire queste procedure consigliate quando si implementano gli hook Apex nei piani procedurali di calcolo dei prezzi per ottimizzare le prestazioni ed evitare risultati imprevisti.

Limiti del governor Apex

Gli hook Apex nei piani procedura vengono eseguiti all'interno della stessa transazione Apex, quindi il timer dell'unità di elaborazione centrale è cumulativo in tutte le operazioni. Tenere presenti i limiti del governor quando si scrive la logica hook, soprattutto per le transazioni con molte voci.

Per i valori limite correnti, vedere Execution Governors and Limits nella Apex Developer Guide.

Eseguire query solo sui tag necessari

Evitare di eseguire query su tag a livello di entità generali come SalesTransactionItem, che restituiscono ogni attributo per ogni elemento. Richiedere invece solo i tag specifici richiesti dalla logica dell'hook.

Non consigliato: Esecuzione di query sui tag generali


// BAD: Returns ALL attributes for every SalesTransactionItem
Map<String, Object> input = new Map<String, Object>{
    'contextId' => contextId,
    'tags' => new List<String>{ 'SalesTransactionItem' }
};
Map<String, Object> output = industriesContext.queryTags(input);
   

Scelta consigliata: Eseguire query solo su tag specifici


// GOOD: Query only the specific tags (attributes) you need
Map<String, Object> input = new Map<String, Object>{
    'contextId' => contextId,
    'tags' => new List<String>{ 'LineItem', 'LineItemQuantity', 'ItemProductCode' }
};
Map<String, Object> output = industriesContext.queryTags(input);
   

Scelta consigliata: Combinazione di tag specifici con leanerQueryTags


// BETTER: Combine specific tags with leanerQueryTags for maximum efficiency
Map<String, Object> input = new Map<String, Object>{
    'contextId' => contextId,
    'tags' => new List<String>{ 'LineItem', 'LineItem$DmlStatus',
        'LineItemQuantity', 'ItemProductCode' }
};
Map<String, Object> output = industriesContext.leanerQueryTags(input);
   

Utilizza leanerQueryTags anziché queryTags

La classe Context.IndustriesContext fornisce due metodi per eseguire query sui dati di contesto. Ove possibile, utilizzare leanerQueryTags per migliorare le prestazioni.

queryTags (heavy): restituisce nodi di contesto completi con mappe di valori tag nidificati e matrici di dataPath. Ogni attributo è racchiuso in una mappa con 6 campi (tagValue, dmlStatus, isDirty, isNodeLevelTag, tagPath, contextDataPathBuilder) per attributo per elemento. Vengono restituiti tutti gli attributi per il tag indipendentemente da ciò di cui si ha bisogno.

leanerQueryTags (leggero): restituisce una struttura compatta con valori di tag piatti e riferimenti ID record basati su indice. I valori dei tag hanno solo 3 campi (tagValue, recordIdIndexesForPath, isNodeLevelTag). Gli ID record vengono duplicati in un elenco recordsInfo condiviso; i nodi vi fanno riferimento in base all'indice.

L'esempio seguente mostra come chiamare leanerQueryTags ed elaborarne l'output.


String contextId = request.ctxInstanceId;
Context.IndustriesContext industriesContext = new Context.IndustriesContext();

Map<String, Object> input = new Map<String, Object>{
    'contextId' => contextId,
    'tags' => new List<String>{ 'LineItem', 'ItemProductCode', 'LineItemQuantity' }
};
Map<String, Object> output = industriesContext.leanerQueryTags(input);

// Access the leaner result structure
Map<String, Object> queryResult = (Map<String, Object>)
    output.get('leanerQueryTagResult');
List<Object> recordsInfo = (List<Object>) output.get('recordsInfo');
List<Object> lineItems = (List<Object>) queryResult.get('LineItem');

// Iterate over tag values — each tag is flat
List<Object> productCodes = (List<Object>) queryResult.get('ItemProductCode');
for (Object obj : productCodes) {
    Map<String, Object> tagNode = (Map<String, Object>) obj;
    String productCode = (String) tagNode.get('tagValue');
    List<Integer> indexes = (List<Integer>) tagNode.get('recordIdIndexesForPath');
    // recordsInfo entries are maps with 'recordId' and 'dmlStatusOrdinal'
    String itemId = (String) ((Map<String, Object>)
        recordsInfo.get(indexes[1])).get('recordId');
}
   

La struttura di output di leanerQueryTags si presenta come segue:


{
  "isSuccess": true,
  "contextId": "...",
  "leanerQueryTagResult": {
    "LineItem": [
      { "recordIdIndexesForPath": [0, 1], "tagValue": "0QLVW000001LxvN4AS", "isNodeLevelTag": false },
      { "recordIdIndexesForPath": [0, 2], "tagValue": "0QLVW000001Lxus4AC", "isNodeLevelTag": false }
    ],
    "ItemProductCode": [
      { "recordIdIndexesForPath": [0, 1], "tagValue": "PROD-001", "isNodeLevelTag": false },
      { "recordIdIndexesForPath": [0, 2], "tagValue": "PROD-002", "isNodeLevelTag": false }
    ]
  },
  "recordsInfo": [
    { "recordId": "0Q0VW0000011qC50AI", "dmlStatusOrdinal": null },
    { "recordId": "0QLVW000001LxvN4AS", "dmlStatusOrdinal": null },
    { "recordId": "0QLVW000001Lxus4AC", "dmlStatusOrdinal": null }
  ]
}
   
Nota
Nota Aggiornare gli hook prezzi Apex esistenti in modo che utilizzino leanerQueryTags anziché queryTags ove possibile.

Migrazione da queryTags a leanerQueryTags

Quando si esegue la migrazione degli hook esistenti da queryTags a leanerQueryTags, applicare le seguenti trasformazioni chiave.

Input: Utilizzare tag singoli anziché tag generali


// Before (queryTags — broad tag):
Map<String, Object> input = new Map<String, Object>{
    'contextId' => contextId,
    'tags' => new List<String>{ 'SalesTransactionItem' }
};
Map<String, Object> output = industriesContext.queryTags(input);
   

// After (leanerQueryTags — specific tags):
Map<String, Object> input = new Map<String, Object>{
    'contextId' => contextId,
    'tags' => new List<String>{ 'LineItem', 'LineItem$DmlStatus',
        'ItemProductCode', 'LineItemQuantity' }
};
Map<String, Object> output = industriesContext.leanerQueryTags(input);
   

Output: Chiave di livello massimo diversa


// Before:
Map<String, Object> queryResult = (Map<String, Object>) output.get('queryResult');
List<Object> items = (List<Object>) queryResult.get('SalesTransactionItem');
   

// After:
Map<String, Object> queryResult = (Map<String, Object>)
    output.get('leanerQueryTagResult');
List<Object> recordsInfo = (List<Object>) output.get('recordsInfo');
List<Object> lineItems = (List<Object>) queryResult.get('LineItem');
   

Accesso nodo: Valori piatti anziché mappe nidificate


// Before (queryTags — nested map extraction):
for (Object itemObj : items) {
    Map<String, Object> itemNode = (Map<String, Object>) itemObj;
    Map<String, Object> tagValueMap = (Map<String, Object>) itemNode.get('tagValue');
    String productCode = (String) ((Map<String, Object>)
        tagValueMap.get('ItemProductCode')).get('tagValue');
    Decimal quantity = (Decimal) ((Map<String, Object>)
        tagValueMap.get('LineItemQuantity')).get('tagValue');
}
   

// After (leanerQueryTags — flat value, iterated per tag):
List<Object> productCodes = (List<Object>) queryResult.get('ItemProductCode');
List<Object> recordsInfo = (List<Object>) output.get('recordsInfo');

for (Object obj : productCodes) {
    Map<String, Object> tagNode = (Map<String, Object>) obj;
    String productCode = (String) tagNode.get('tagValue');
    List<Integer> indexes = (List<Integer>) tagNode.get('recordIdIndexesForPath');
    String itemId = (String) ((Map<String, Object>)
        recordsInfo.get(indexes[1])).get('recordId');
}
   

ID record: Riferimenti indice anziché dataPath


// Before (queryTags):
List<Object> dataPath = (List<Object>) itemNode.get('dataPath');
// dataPath = ['contextId', 'txnId', 'itemId'] — 3 elements, first is contextId
dataPath.remove(0);
String transactionId = (String) dataPath.get(0);
   

// After (leanerQueryTags):
List<Object> recordsInfo = (List<Object>) output.get('recordsInfo');
List<Integer> indexes = (List<Integer>) tagNode.get('recordIdIndexesForPath');
String transactionId = (String) ((Map<String, Object>)
    recordsInfo.get(indexes[0])).get('recordId');
String itemId = (String) ((Map<String, Object>)
    recordsInfo.get(indexes[1])).get('recordId');
   

Utilizzo dello schema tagIdIndexMap

Quando si elaborano più tag in un unico loop, utilizzare un tagIdIndexMap per mappare ogni nome di tag alla sua posizione nella matrice di recordIdIndexesForPath. Ciò consente di estrarre correttamente gli ID a ogni livello gerarchico:


Map<String, Integer> tagIdIndexMap = new Map<String, Integer>{
    'LineItem' => 1,            // item-level tag, ID at index 1
    'LineItem$DmlStatus' => 1,  // item-level tag, ID at index 1
    'LineItemQuantity' => 1,    // item-level tag, ID at index 1
    'BusinessUnit__c' => 0,     // transaction-level tag, ID at index 0
    'Contract' => 0             // transaction-level tag, ID at index 0
};
   
  • Indice 0 = livello transazione (il percorso ha un elemento: [txnId])
  • Index 1 = item-level (il percorso ha due elementi: [txnId, itemId])
  • Indice 2 = livello dettaglio (il percorso ha tre elementi: [txnId, itemId, detailId])

Filtro degli elementi eliminati

Ignorare gli elementi eliminati all'inizio del loop di iterazione per evitare elaborazioni inutili. Richiedere LineItem$DmlStatus come tag separato nella query:


private static final String DML_DELETED = 'DELETED';

for (Map<String, Object> item : salesTransactionInstance.salesTransactionItems) {
    String dmlStatus = (String) item.get('LineItem$DmlStatus');

    if (dmlStatus == DML_DELETED) {
        continue; // Skip deleted items
    }

    // Process active items...
}
   

Lettura di $DmlStatus come tag separato

Quando si eseguono query su tag specifici (approccio consigliato), lo stato DML non viene incorporato nei metadati dei tag. È necessario richiedere LineItem$DmlStatus come tag separato. Questo vale sia per queryTags che per leanerQueryTags.


// Add LineItem$DmlStatus to your tags list
'tags' => new List<String>{ 'LineItem', 'LineItem$DmlStatus', 'ItemProductCode' }

// Access it like any other tag in the result
Map<String, Object> dmlNode = (Map<String, Object>) dmlStatusValues.get(i);
String dmlStatus = String.valueOf(dmlNode.get('tagValue'));
   
 
Caricamento
Salesforce Help | Article