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.

DatentypFilter-Feld (S/4)Filter-Feld (ECC)Empfehlung
BelegeDocumentDate, PostingDateBUDATPostingDate für finanzielle Konsistenz
JournaleinträgeCreatedDateTime, ModifiedDateTimeERDAT, AEDATModifiedDateTime für Änderungserkennung
MaterialstämmeLastChangedDateTimeLAEDALastChangedDateTime (S/4 bevorzugt)
Debitoren/KreditorenChangedOnAEDATChangedOn 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:00Z

1.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-01

Sammelt 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:

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:

deltaLink-Mechanismus:

{
  "@odata.context": "...",
  "@odata.deltaLink": "...$deltatoken=12345",
  "value": [...]
}

Vorteile:

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:

PhaseHäufigkeitFilterZiel
Initial LoadEinmaligKeine (alle Daten)Basis-Datensatz etablieren
Regular DeltaAlle 6 Stunden$filter=ModifiedDateTime ge [letzte Ausführung]Inkrementelle Updates
Periodic Full RefreshWöchentlichKeine (alle Daten)Datenintegritätsprüfung
Overlap Window24 Stunden$filter=ModifiedDateTime ge [letzter Delta - 24h]Fehlgeschlagene Änderungen fangen

Fehlerresilienz:


2. Paging

2.1 Client-Driven: $top / $skip

Der Client steuert explizit die Paginierung durch Offset und Limit.

Syntax:

$skip=5000&$top=1000

Vorteil: Einfache Implementierung, direkte Kontrolle.

Nachteil:

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
ENDDO

Vorteil: Server-seitige Optimierung, effizient für große Datenmengen.

2.3 Empfohlene Seitengrößen

Entity SetEmpfohlene $topBegründungMax. Payload
Verkaufsbelege1.000Balance: Performance vs. Requests~2 MB
Positionen5.000Größere Granularität, weniger komplexe Struktur~3 MB
Journaleinträge5.000Standardeinstellung für Finance-Tabellen~4 MB
Materialstämme2.000Komplexe Struktur, ggf. viele Anhänge~2.5 MB
Debitor/Kreditor3.000Moderate 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:

Use-Case: Gleichzeitiger Abruf mehrerer Entity Sets ohne Serialisierung.


4. Fehlerbehandlung

Standardisierte HTTP-Status-Codes und korrespondierende Handling-Strategien:

HTTP-CodeOData-StatusBedeutungAktion
200OKAnfrage erfolgreichDaten verarbeiten
204No ContentErfolg, keine DatenWeiterfahren
400Bad RequestMalformed RequestQuery-Syntax überprüfen, nicht retry
401UnauthorizedAuthentifizierung fehlgeschlagenToken refresh, re-auth
403ForbiddenZugriff verweigertBerechtigungsprüfung, Admin kontaktieren
404Not FoundEntity existiert nichtGgf. mit Fallback-Entity arbeiten
408Request TimeoutTimeout auf ServerRetry mit exponential backoff
500Internal Server ErrorServer-FehlerRetry mit exponential backoff
503Service UnavailableMaintenance/ÜberlastRetry 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:


Siehe auch: 06 - Authentication & Connectivity | 08 - Re-Integration (Write-Back)


**