Sie befinden sich hier:
Bewährte Vorgehensweisen für Apex Pricing Hooks
Befolgen Sie diese bewährten Vorgehensweisen, wenn Sie Apex Hooks in Ihre Preisgestaltungsverfahrenspläne implementieren, um die Leistung zu optimieren und unerwartete Ergebnisse zu vermeiden.
Apex-Obergrenzen
Apex Hooks in Verfahrensplänen werden in derselben Apex Transaktion ausgeführt, sodass der Timer der zentralen Verarbeitungseinheit für alle Vorgänge kumuliert. Beachten Sie beim Schreiben von Hook-Logik die Obergrenzen, insbesondere bei Transaktionen mit vielen Belegposten.
Aktuelle Grenzwerte finden Sie im Apex Developer Guide unter Execution Governors and Limits.
Nur die benötigten Tags abfragen
Vermeiden Sie die Abfrage breiter Tags auf Einheitenebene wie SalesTransactionItem, die jedes Attribut für jedes Element zurückgeben. Fordern Sie stattdessen nur die spezifischen Tags an, die für Ihre Hook-Logik erforderlich sind.
Nicht empfohlen: Abfragen breiter Tags
// 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);
Empfohlen: Nur bestimmte Tags abfragen
// 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);
Empfohlen: Kombinieren bestimmter Tags mit 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);
Verwenden von leanerQueryTags anstelle von queryTags
Die Klasse Context.IndustriesContext bietet zwei Methoden zum Abfragen von Kontextdaten. Verwenden Sie nach Möglichkeit leanerQueryTags für eine bessere Leistung.
queryTags (heavy): Gibt vollständige Kontextknoten mit verschachtelten Tag-Wert-Zuordnungen und dataPath-Arrays zurück. Jedes Attribut wird in eine Karte mit 6 Feldern (tagValue, dmlStatus, isDirty, isNodeLevelTag, tagPath, contextDataPathBuilder) pro Attribut und Element eingeschlossen. Alle Attribute für das Tag werden unabhängig davon zurückgegeben, was Sie benötigen.
leanerQueryTags (lightweight): Gibt eine kompakte Struktur mit Flat-Tag-Werten und indexbasierten Datensatz-ID-Verweisen zurück. Tag-Werte weisen nur 3 Felder (tagValue, recordIdIndexesForPath, isNodeLevelTag) auf. Datensatz-IDs werden in eine freigegebene recordsInfo-Liste dedupliziert. Knoten verweisen auf sie nach Index.
Im folgenden Beispiel wird gezeigt, wie leanerQueryTags aufgerufen und seine Ausgabe verarbeitet wird.
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');
}
Die leanerQueryTags sieht wie folgt aus:
{
"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 }
]
}
Migrieren von queryTags zu leanerQueryTags
Wenden Sie beim Migrieren vorhandener Hooks von queryTags zu leanerQueryTags die folgenden Schlüsseltransformationen an.
Eingabe: Verwenden einzelner Tags anstelle von breiten Tags
// 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);
Ausgabe: Unterschiedlicher Schlüssel der obersten Ebene
// 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');
Knotenzugriff: Flache Werte anstelle von verschachtelten Karten
// 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');
}
Datensatz-IDs: Indexverweise anstelle von 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');
Verwenden des Musters tagIdIndexMap
Wenn Sie mehrere Tags in einer einzelnen Schleife verarbeiten, ordnen Sie jeden Tagnamen mithilfe eines tagIdIndexMap seiner Position im recordIdIndexesForPath-Array zu. Dadurch können Sie IDs auf jeder Hierarchieebene richtig extrahieren:
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
};
- Index 0 = Transaktionsebene (der Pfad weist ein Element auf: [
txnId]) - Index 1 = Elementebene (der Pfad weist zwei Elemente auf: [
txnId,itemId]) - Index 2 = Detailebene (der Pfad besteht aus drei Elementen: [
txnId,itemId,detailId])
Filtern gelöschter Elemente
Überspringen Sie gelöschte Elemente zu Beginn Ihrer Iterationsschleife, um unnötige Verarbeitung zu vermeiden. Fordern Sie LineItem$DmlStatus als separates Tag in Ihrer Abfrage an:
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...
}
Lesen von $DmlStatus als separates Tag
Beim Abfragen bestimmter Tags (dem empfohlenen Ansatz) wird der DML-Status nicht in die Tag-Metadaten eingebettet. Sie müssen LineItem$DmlStatus als separates Tag anfordern. Dies gilt für queryTags und 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'));

