Você está aqui:
Práticas recomendadas para ganchos de precificação do Apex
Siga estas práticas recomendadas ao implementar ganchos do Apex em seus planos de procedimento de precificação para otimizar o desempenho e evitar resultados inesperados.
Limites do regulador do Apex
Os ganchos do Apex em planos de procedimento são executados na mesma transação do Apex, de modo que o temporizador da unidade de processamento central é cumulativo em todas as operações. Lembre-se dos limites do controlador ao escrever lógica de gancho, especialmente para transações com muitos itens de linha.
Para os valores de limite atuais, consulte Controladores e limites de execução no Guia do desenvolvedor do Apex.
Consultar apenas as marcas necessárias
Evite consultar marcas no nível da entidade, como SalesTransactionItem, que retornam todos os atributos de cada item. Em vez disso, solicite apenas as marcas específicas que sua lógica de gancho exige.
Não recomendado: Consultar marcas largas
// 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);
Recomendado: Consultar apenas marcações específicas
// 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);
Recomendado: Combine marcas específicas com 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);
Usar leanerQueryTags em vez de queryTags
A classe Context.IndustriesContext fornece dois métodos para consultar dados de contexto. Use leanerQueryTags sempre que possível para melhor desempenho.
queryTags (heavy) — Retorna nós de contexto completos com mapas de valor de marcação aninhados e matrizes de dataPath. Cada atributo é agrupado em um mapa com 6 campos (tagValue, dmlStatus, isDirty, isNodeLevelTag, tagPath, contextDataPathBuilder) por atributo por item. Todos os atributos da marca são retornados independentemente do que você precisa.
leanerQueryTags (lightweight) – retorna uma estrutura compacta com valores de marca simples e referências de ID de registro baseado em índice. Os valores de marcação têm apenas 3 campos (tagValue, recordIdIndexesForPath, isNodeLevelTag). Os IDs de registro são desduplicados em uma lista de recordsInfo compartilhada; os nós fazem referência a eles por índice.
O exemplo a seguir mostra como chamar leanerQueryTags e processar sua saída.
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');
}
A estrutura de saída do leanerQueryTags é assim:
{
"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 }
]
}
Migrar de queryTags para leanerQueryTags
Ao migrar ganchos existentes de queryTags para leanerQueryTags, aplique estas transformações de chave.
Entrada: Usar marcas individuais em vez de marcas largas
// 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);
Saída: Chave de nível superior diferente
// 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');
Acesso ao nó: Valores uniformes em vez de mapas aninhados
// 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');
}
IDs de registro: Referências de índice em vez de 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');
Usar o padrão tagIdIndexMap
Ao processar várias marcas em um único loop, use um tagIdIndexMap para mapear cada nome de marca para sua posição na matriz de recordIdIndexesForPath. Isso permite que você extraia corretamente IDs em cada nível de hierarquia:
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
};
- Índice 0 = nível de transação (o caminho tem um elemento: [
txnId]) - Índice 1 = nível de item (o caminho tem dois elementos: [
txnId,itemId]) - Índice 2 = nível de detalhes (o caminho tem três elementos: [
txnId,itemId,detailId])
Filtrar itens excluídos
Ignore itens excluídos no início do seu loop de iteração para evitar processamento desnecessário. Solicitar LineItem$DmlStatus como uma marca separada na sua consulta:
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...
}
Ler $DmlStatus como uma marca separada
Ao consultar marcações específicas (a abordagem recomendada), o status DML não é integrado aos metadados da marcação. Você deve solicitar LineItem$DmlStatus como uma tag separada. Isso se aplica tanto a queryTags quanto a 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'));
