Delta-Logik & Paging
Inkrementelle Abfragen, Server-Side Paging und Änderungstoken-Logik.
1. Delta-Strategien
1.1 $filter auf Zeitstempel
Zeitstempel-basierte Filter ermöglichen es, nur veränderte Datensätze seit dem letzten Abruf zu laden. Dies ist die fundamentalste Delta-Implementierung in OData.
| Datentyp | Filter-Feld (S/4) | Filter-Feld (ECC) | Empfehlung |
|---|---|---|---|
| Belege | DocumentDate, PostingDate | BUDAT | PostingDate für finanzielle Konsistenz |
| Journaleinträge | CreatedDateTime, ModifiedDateTime | ERDAT, AEDAT | ModifiedDateTime für Änderungserkennung |
| Materialstämme | LastChangedDateTime | LAEDA | LastChangedDateTime (S/4 bevorzugt) |
| Debitoren/Kreditoren | ChangedOn | AEDAT | ChangedOn für umfassende Änderungen |
OData v2 DateTime-Format:
$filter=ModifiedDateTime ge datetime'2026-04-08T14:30:00'OData v4 DateTime-Format (ISO 8601):
$filter=ModifiedDateTime ge 2026-04-08T14:30:00Z1.2 Zwei-Stufen-Delta (analog ABAP-Logik)
Das Zwei-Stufen-Delta-Verfahren emuliert die klassische ABAP-Logik und ermöglicht effiziente Batching bei komplexen Filterszenarien.
Stufe 1: Primärer Filter für Clearing-Datum
$filter=ClearingDate ge 2026-04-01Sammelt alle Clearing-Journaleinträge seit dem Referenzdatum. Rückgabeergebnis: Liste von ClearingJournalEntry-IDs.
Stufe 2: Sekundärer Filter mit IN-Operator (OData v4)
$filter=ClearingJournalEntry in ('00000001', '00000002', '00000003')Nutzt die aus Stufe 1 gewonnenen IDs für präzise Filterung. Dies vermeidet Duplikate und reduziert Netzwerkverkehr erheblich.
OData v4 IN-Operator-Syntax:
Funktioniert mit komma-separierten Werten in Klammern
Maximale Listenlänge beträgt typischerweise 1.000 Einträge (SAP-abhängig)
Empfehlung: Batches à 500 Einträge für optimale Performance
1.3 SAP Change Tracking (S/4 HANA only)
SAP S/4 HANA bietet natives Change Tracking über Delta Tokens und deltaLink-Mechanismen, die direkt vom OData-Service verwaltet werden.
Delta-Token Konzept:
Opaque Token, das den Zustand zum Abfragezeitpunkt repräsentiert
Initialer Abruf:
$filter=IsActiveEntity eq true&$deltatoken=0Nachfolgende Abrufe verwenden das erhaltene Token
deltaLink-Mechanismus:
{
"@odata.context": "...",
"@odata.deltaLink": "...$deltatoken=12345",
"value": [...]
}Vorteile:
Automatische Behandlung gelöschter Datensätze
SAP-native Optimierung
Reduzierte Datenlast durch Server-seitige Filterung
Einschränkung: Nur auf S/4 HANA verfügbar; klassisches ECC unterstützt diese Funktionalität nicht.
1.4 Kombination Vollladen + Delta
Optimale Strategie für produktive Umgebungen mit hohem Datenvolumen:
| Phase | Häufigkeit | Filter | Ziel |
|---|---|---|---|
| Initial Load | Einmalig | Keine (alle Daten) | Basis-Datensatz etablieren |
| Regular Delta | Alle 6 Stunden | $filter=ModifiedDateTime ge [letzte Ausführung] | Inkrementelle Updates |
| Periodic Full Refresh | Wöchentlich | Keine (alle Daten) | Datenintegritätsprüfung |
| Overlap Window | 24 Stunden | $filter=ModifiedDateTime ge [letzter Delta - 24h] | Fehlgeschlagene Änderungen fangen |
Fehlerresilienz:
Bei fehlgeschlagener Delta-Abfrage auf den 24-Stunden-Fenster ausweichen
Nach erfolgreicher Resynchronisation zur 6h-Cadence zurückkehren
Wöchentliche Vollladung erzwingt Konsistenzprüfung
2. Paging
2.1 Client-Driven: $top / $skip
Der Client steuert explizit die Paginierung durch Offset und Limit.
Syntax:
$skip=5000&$top=1000Vorteil: Einfache Implementierung, direkte Kontrolle.
Nachteil:
Performance-Degradation bei großen Offsets (bis zu O(n) auf Server-Seite)
Bei > 100.000 Datensätze stark zu vermeiden
Nicht geeignet für kontinuierliche Resyncs
Empfehlung: Nur für kleine Datenmengen (< 50.000 Datensätze total) oder initiale Explorationen verwenden.
2.2 Server-Driven: __next (v2) / @odata.nextLink (v4)
Der Server steuert Paginierung durch Cursor- oder Token-basierte Links.
OData v2 Format:
{
"d": {
"results": [...],
"__next": "https://sap.example.com/odata/v2/SalesOrders?$skip=5000&$top=1000"
}
}OData v4 Format:
{
"value": [...],
"@odata.nextLink": "https://sap.example.com/odata/v4/SalesOrders?$skip=5000&$top=1000"
}Implementierung:
DO
response = GET(url)
APPEND response.value TO result
IF response.@odata.nextLink IS NOT INITIAL
url = response.@odata.nextLink
ELSE
EXIT
ENDIF
ENDDOVorteil: Server-seitige Optimierung, effizient für große Datenmengen.
2.3 Empfohlene Seitengrößen
| Entity Set | Empfohlene $top | Begründung | Max. Payload |
|---|---|---|---|
| Verkaufsbelege | 1.000 | Balance: Performance vs. Requests | ~2 MB |
| Positionen | 5.000 | Größere Granularität, weniger komplexe Struktur | ~3 MB |
| Journaleinträge | 5.000 | Standardeinstellung für Finance-Tabellen | ~4 MB |
| Materialstämme | 2.000 | Komplexe Struktur, ggf. viele Anhänge | ~2.5 MB |
| Debitor/Kreditor | 3.000 | Moderate Komplexität | ~2.5 MB |
Faustregel: $top=5.000 ist für die meisten Fälle eine sichere Wahl.
3. $batch Requests
Mehrere OData-Anfragen können in einer einzigen HTTP-Anfrage kombiniert werden. Dies reduziert Latenz und Netzwerk-Overhead erheblich.
Multipart-Request-Struktur (OData v2):
POST /odata/v2/$batch HTTP/1.1
Content-Type: multipart/mixed; boundary=batch_12345
--batch_12345
Content-Type: application/http
Content-Transfer-Encoding: binary
GET SalesOrders?$filter=Status eq 'Open' HTTP/1.1
--batch_12345
Content-Type: application/http
Content-Transfer-Encoding: binary
GET Customers('C001') HTTP/1.1
--batch_12345--Response-Struktur:
HTTP/1.1 202 Accepted
Content-Type: multipart/mixed; boundary=response_12345
--response_12345
Content-Type: application/http
HTTP/1.1 200 OK
{... erste Response ...}
--response_12345
Content-Type: application/http
HTTP/1.1 200 OK
{... zweite Response ...}
--response_12345--Limitierungen:
Default-Payload-Limit: 10 MB pro $batch-Request
Maximum Anfragen pro Batch: typ. 100-500 (SAP-konfigurierbar)
Empfehlung: ≤ 50 Anfragen pro Batch für Zuverlässigkeit
Use-Case: Gleichzeitiger Abruf mehrerer Entity Sets ohne Serialisierung.
4. Fehlerbehandlung
Standardisierte HTTP-Status-Codes und korrespondierende Handling-Strategien:
| HTTP-Code | OData-Status | Bedeutung | Aktion |
|---|---|---|---|
| 200 | OK | Anfrage erfolgreich | Daten verarbeiten |
| 204 | No Content | Erfolg, keine Daten | Weiterfahren |
| 400 | Bad Request | Malformed Request | Query-Syntax überprüfen, nicht retry |
| 401 | Unauthorized | Authentifizierung fehlgeschlagen | Token refresh, re-auth |
| 403 | Forbidden | Zugriff verweigert | Berechtigungsprüfung, Admin kontaktieren |
| 404 | Not Found | Entity existiert nicht | Ggf. mit Fallback-Entity arbeiten |
| 408 | Request Timeout | Timeout auf Server | Retry mit exponential backoff |
| 500 | Internal Server Error | Server-Fehler | Retry mit exponential backoff |
| 503 | Service Unavailable | Maintenance/Überlast | Retry mit exponential backoff, später erneut versuchen |
Retry-Strategie: Exponential Backoff
attempt = 0
max_attempts = 5
base_delay = 1 (Sekunde)
DO WHILE attempt < max_attempts
TRY
response = ODataRequest(...)
IF response.status IN (200, 204)
RETURN response
ELSE IF response.status IN (408, 500, 503)
attempt += 1
delay = base_delay * (2 ^ attempt) + RANDOM(0, 1)
WAIT delay seconds
ELSE
RAISE error (non-retriable)
ENDIF
CATCH exception
attempt += 1
WAIT base_delay * (2 ^ attempt)
ENDTRY
ENDDO
RAISE "Max retries exceeded"Parameter:
Base Delay: 1 Sekunde
Max Attempts: 5
Jittering: ±1 Sekunde, um Thundering Herd zu vermeiden
Maximale Wartezeit: 32+ Sekunden (für Attempt 5)
Siehe auch: 06 - Authentication & Connectivity | 08 - Re-Integration (Write-Back)
**