Datenfluss

Wie die DataBridge-Jobs ineinandergreifen — Zeitplan, Filter, Response-Jobs und Löschverarbeitung.

Diese Seite richtet sich an die IT-Administration — vertiefende technische Referenz mit Job-Filtersyntax und Zeitplänen.

Diese Seite zeigt, wie die Daten fließen. Welche Felder dabei zugeordnet werden, steht auf den Mapping-Detailseiten.

Grundprinzip

Jeder Job der DataBridge ist ein eigenständiger, zeitgesteuerter Lauf:

flowchart LR
  A["Zeitplan<br/><code>Schedule</code>"] --> B["Quelle lesen<br/><code>SourceConnection</code>"]
  B --> C["Filter anwenden<br/><code>Filter</code> + <code>%watermark%</code>"]
  C --> D["Mapping ausführen<br/>Feldzuordnung + Transformation"]
  D --> E["Key-Auflösung<br/>Datensatz im Ziel finden"]
  E --> F["Schreiben<br/><code>TargetConnection</code>"]
  F --> G["Watermark fortschreiben<br/><code>WatermarkField</code>"]
  G -.->|falls gesetzt| H["Response-Job starten<br/><code>ResponseJob</code>"]

Die Reihenfolge innerhalb eines Laufs steuert das Feld Order (110 – 760). Stammdaten laufen zuerst (110 – 190), damit die Lookups der späteren Jobs (Firma, Angebot, Abo) ihre Referenzdatensätze bereits vorfinden.

Die meisten Jobs laufen alle 2 Minuten (0 */2 * * * *), die Jobs rund um Verkaufschancen und Angebotsaktivierung alle 3 Minuten (0 */3 * * * *).

Gesamtfluss

flowchart TB
  subgraph S1["1 · Stammdaten &nbsp;(Order 110–190)"]
    direction LR
    ST["BC Referenztabellen<br/>Länder · Sprachen · Anreden<br/>Verkäufer · Positionen<br/>Rabattgruppen"] --> STC["CE Wertelisten<br/><code>wysa_country</code>, <code>wysa_language</code>,<br/><code>wysa_bcsalutation</code>, <code>wysa_salesperson</code>, …"]
    IT["BC Verkaufschancen-Elemente<br/><code>acdopportunityelements</code>"] --> ITC["CE <code>product</code>"]
  end

  subgraph S2["2 · Geschäftspartner &nbsp;(Order 220–241, 410–440, 520–530)"]
    direction LR
    CEA["CE <code>account</code> / <code>contact</code>"] -->|"neu: <code>CEAccounts</code>, <code>CEContacts</code>"| BCA["BC <code>acdcontactscomp</code> / <code>acdcontacts</code>"]
    CEA -->|"geändert: <code>CEAccountUpdates</code>, <code>CEContactsUpdates</code>"| BCA
    BCA -->|"Response: Nummer zurück"| CEA
    BCA -->|"<code>BCAccounts</code>, <code>BCContacts</code>"| CEA
  end

  subgraph S3["3 · Verkaufschancen &nbsp;(Order 260–261, 710–760)"]
    direction LR
    CEO["CE <code>opportunity</code><br/><code>opportunityproduct</code>"] -->|"<code>CEOpportunities</code><br/><code>CEOpportunityProducts</code>"| BCO["BC <code>acdopportunities</code><br/><code>acdopportunitycalculationelements</code>"]
    BCO -->|"Response"| CEO
  end

  subgraph S4["4 · Angebote &amp; Abos &nbsp;(Order 550–625)"]
    direction LR
    BCQ["BC <code>acdsalesheaders</code><br/><code>acdsalescalculationelements</code><br/><code>serviceObjects</code> / <code>serviceCommitments</code>"] --> CEQ["CE <code>quote</code> / <code>quotedetail</code><br/><code>wysa_bcserviceobject(commitment)</code>"]
  end

  subgraph S5["5 · Löschungen &nbsp;(Order 420–690)"]
    direction LR
    LOG["BC Änderungsprotokoll<br/><code>acdlogentries</code>"] --> DEL["CE: Datensatz löschen<br/><code>account</code>, <code>contact</code>, <code>product</code>,<br/><code>quote</code> deaktivieren/schließen,<br/><code>quotedetail</code> löschen"]
  end

  S1 --> S2 --> S3 --> S4 --> S5

Muster 1 — Referenzdaten BC → CE

Der einfachste Fall: BC ist führendes System, CE liest nur mit.

sequenceDiagram
  participant BC as Business Central
  participant DB as DataBridge
  participant CE as Customer Engagement
  DB->>BC: GET api page<br/>?$filter=lastModifiedDateTime gt %watermark%
  BC-->>DB: geänderte Datensätze
  DB->>DB: Mapping + Lookup auf CE-Key
  DB->>CE: Upsert (anlegen oder aktualisieren)
  DB->>DB: Watermark = höchstes lastModifiedDateTime

Die Abgrenzung erfolgt über das Watermark: der Job merkt sich den höchsten Wert von WatermarkField (lastModifiedDateTime, Typ datetime) des letzten Laufs und liest beim nächsten Mal nur, was seitdem geändert wurde.

Betroffene Mappings: alle BC*-Mappings außer den Delete- und Response-Varianten.

Die Jobs in Gegenrichtung (CE*-Mappings) brauchen kein Watermark-Feld: Für Dataverse-Quellen nutzt die DataBridge das Change Tracking der Plattform und erhält damit nur die seit dem letzten Lauf geänderten Datensätze.

Muster 2 — CE → BC mit Response-Job

Legt der Vertrieb in CE eine Firma, einen Kontakt oder eine Verkaufschance an, existiert diese in BC noch nicht. BC vergibt beim Anlegen die Nummer und die SystemId — diese müssen zurück nach CE. Genau dafür gibt es den Response-Job:

sequenceDiagram
  participant CE as Customer Engagement
  participant DB as DataBridge
  participant BC as Business Central

  Note over DB: Job "accountsnewfromce" (Order 220)
  DB->>CE: lies account
  Note right of DB: Filter:<br/>wysa_bcsystemid IS NULL<br/>UND wysa_sync2bc = "Freigegeben"
  CE-->>DB: neue, freigegebene Firmen
  DB->>BC: POST acdcontactscomp
  BC-->>DB: number, id (SystemId)

  Note over DB: ResponseJob "accountsresponsefrombc" (Order 221)
  DB->>BC: lies acdcontactscomp
  BC-->>DB: number, id
  DB->>CE: schreibe wysa_bccontactnumber, wysa_bcsystemid
  Note right of CE: Ab jetzt greift<br/>"accountupdatesfromce" (Order 520)

Der entscheidende Mechanismus ist das Feld wysa_bcsystemid:

  • leer → der Datensatz ist BC noch unbekannt → der Neu-Job greift (CEAccounts, CEContacts, CEOpportunities, CEOpportunityProducts)
  • gefüllt → der Datensatz existiert in BC → der Update-Job greift (CEAccountUpdates, CEContactsUpdates, CEOpportunityProductsUpdates)

Zusätzlich muss wysa_sync2bc auf „Freigegeben" stehen — siehe Freigabe nach Business Central.

Response-Jobs sind bewusst mit IsActive = false konfiguriert. Sie werden nicht über den eigenen Zeitplan gestartet, sondern ausschließlich vom vorgelagerten Job über dessen Feld ResponseJob aufgerufen.

Auslösender JobOrderResponse-JobOrder
accountsnewfromce220accountsresponsefrombc221
contactsnewfromce240contactsresponsefrombc241
opportunitiesnewfromce260opportunitiesresponsefrombc261
opportunityproductsnewfromce710opportunityproductsresponsefrombc760

Muster 3 — Löschungen über das Änderungsprotokoll

Ein gelöschter Datensatz taucht in der normalen API Page nicht mehr auf — er kann also nicht per Abgleich erkannt werden. Stattdessen liest die DataBridge das BC-Änderungsprotokoll acdlogentries:

flowchart LR
  DEL["Löschung in BC"] --> LOG["Eintrag in<br/><code>acdlogentries</code><br/>tableId + operation"]
  LOG --> F{"Filter je Job"}
  F -->|"tableId 5050 (Kontakt)"| A["<code>BCAccountsDelete</code><br/><code>BCContactsDelete</code>"]
  F -->|"tableId 72077781 (Artikel)"| P["<code>BCProductsDelete</code>"]
  F -->|"tableId 36 (Angebot)"| Q["<code>BCSalesQuotesDelete</code>"]
  F -->|"tableId 72077783 (Kalkulation)"| K["<code>BCSalesCalculationElementsDelete</code>"]
  A --> X["Mapping setzt<br/><code>statecode</code> / <code>statuscode</code><br/>→ Datensatz wird <b>deaktiviert</b>"]
  P --> X
  Q --> Y["Job-Feld <code>Action = Delete</code><br/>→ Datensatz wird <b>gelöscht</b>"]
  K --> Y

Diese Jobs unterscheiden sich in zwei Punkten von den übrigen:

  • Die Quelle ist immer acdlogentries, nie die Fachtabelle. Der Filter grenzt über tableId die betroffene BC-Tabelle ab, z. B. {{lastModifiedDateTime gt %watermark%}} and tableId eq 5050 für Kontakte/Firmen. Als Schlüssel dient recordId → wysa_bcsystemid.
  • Es gibt zwei Varianten, wie im Ziel reagiert wird:
VarianteJobsVerhalten in CE
Deaktivieren (kein Action-Feld)accountsfrombcdelete, contactsfrombcdelete, productsfrombcdeleteDas Mapping setzt per DefaultValue den statecode auf 1 und den statuscode auf einen Inaktiv-Wert — der Datensatz bleibt erhalten, wird aber inaktiv gesetzt. Firma und Kontakt verwenden den lösungseigenen Statusgrund 799840001, das Produkt den Dataverse-Standardwert 2
Schließen (kein Action-Feld)salesquotesfrombcdeleteDas Mapping setzt statecode = 3 (Geschlossen) und statuscode = 6 (Storniert) — das Angebot bleibt erhalten
Löschen (Action = Delete)salescalculationelementsfrombcdeleteDie DataBridge löscht den Datensatz im Ziel

Stammdaten wie Firma, Kontakt und Produkt werden also nie hart gelöscht — für Historie und referenzielle Integrität in CE ist das wichtig. Angebote werden storniert, nur Angebotspositionen werden entfernt.

Sonderfall — Angebot aktivieren

BCSalesQuotesActivate (Order 625) ist kein Datenabgleich, sondern eine Statusänderung. Der Job liest ebenfalls acdlogentries, filtert aber auf tableId eq 36 and operation eq 'TRANSFERRED' — also auf den Moment, in dem in BC aus einem Angebot ein Auftrag wird — und setzt daraufhin den Status des zugehörigen quote in CE.

Ausführungsreihenfolge und Takt

Die Jobs tragen eine Ordnungsnummer (Order), die festlegt, in welcher Folge sie innerhalb eines Durchlaufs abgearbeitet werden. Darauf beruhen die Reihenfolgeabhängigkeiten der Integration: Stammdaten vor Belegen, Firma vor Kontakt, Kontakt vor Verkaufschance.

OrderJobBereichTakt
110countriesfrombcStammdaten — Länder2 Min
115languagesfrombcStammdaten — Sprachen2 Min
120salutationsfrombcStammdaten — Anreden2 Min
125customerdiscountgroupsfrombcStammdaten — Rabattgruppen2 Min
130salespersonsfrombcStammdaten — Verkäufer2 Min
135positionsfrombcStammdaten — Organisationsebenen2 Min
190opportunityelementsfrombcVerkaufschance — Kalkulationselemente2 Min
220accountsnewfromceFirma — neu nach BC2 Min
↳ 221accountsresponsefrombcFirma — Rückmeldungnach 220
240contactsnewfromceKontakt — neu nach BC2 Min
↳ 241contactsresponsefrombcKontakt — Rückmeldungnach 240
260opportunitiesnewfromceVerkaufschance — neu nach BC2 Min
↳ 261opportunitiesresponsefrombcVerkaufschance — Rückmeldungnach 260
410accountsfrombcFirma — aus BC2 Min
420accountsfrombcdeleteFirma — Löschung2 Min
430contactsfrombcKontakt — aus BC2 Min
440contactsfrombcdeleteKontakt — Löschung2 Min
450productsfrombcdeleteStammdaten — Produkte deaktivieren2 Min
520accountupdatesfromceFirma — Änderungen nach BC2 Min
530contactupdatesfromceKontakt — Änderungen nach BC2 Min
550serviceobjectsfrombcAbonnement — Abonnements2 Min
560servicecommitmentsfrombcAbonnement — Zeilen2 Min
610salesquotesfrombcAngebot — Angebote aus BC2 Min
620salescalculationelementsfrombcAngebot — Positionen aus BC2 Min
621salescalculationelementsfrombcdeleteAngebot — Positionen löschen2 Min
625activatesalesquotesfrombcAngebot — gewonnene Angebote3 Min
690salesquotesfrombcdeleteAngebot — Angebote stornieren2 Min
710opportunityproductsnewfromceVerkaufschance — Positionen neu3 Min
750opportunityproductsupdatesfromceVerkaufschance — Positionen ändern3 Min
↳ 760opportunityproductsresponsefrombcVerkaufschance — Rückmeldungnach 710

Mit ↳ gekennzeichnet sind die vier Response-Jobs. Sie haben keinen eigenen Zeitplan, sondern werden unmittelbar von ihrem auslösenden Job gestartet und folgen damit dessen Takt.

Die Ordnungsnummer sortiert nur innerhalb eines Takts

Das ist die wichtigste Einschränkung an der Tabelle oben: Es gibt zwei Zeitpläne. 23 Jobs laufen alle zwei Minuten, drei alle drei Minuten — und diese drei sind fett hervorgehoben.

flowchart TB
  subgraph M0["Minute 0, 6, 12, 18 …"]
    A0["<b>alle</b> Jobs<br/>2-Minuten- und 3-Minuten-Gruppe<br/>→ Ordnungsnummer gilt durchgehend"]
  end
  subgraph M2["Minute 2, 4, 8, 10 …"]
    A2["nur die 23 Jobs der<br/><b>2-Minuten-Gruppe</b>"]
  end
  subgraph M3["Minute 3, 9, 15, 21 …"]
    A3["nur die 3 Jobs der<br/><b>3-Minuten-Gruppe</b><br/>625, 710, 750"]
  end

Die Ordnungsnummer legt also nur die Folge der Jobs fest, die im selben Tick laufen. Die beiden Gruppen treffen sich alle sechs Minuten.

Praktisch bedeutet das für die drei Jobs im Drei-Minuten-Takt:

JobBraucht Vorarbeit vonKonsequenz
710 · Positionen neu nach BC190 (Kalkulationselemente) und 260 / 261 (Verkaufschance)läuft in einem eigenen Tick — die Vorarbeit stammt aus einem früheren Durchlauf
750 · Positionen ändern710, 760läuft im selben Tick wie 710, hier gilt die Ordnungsnummer
625 · gewonnene Angebote610 (Angebote aus BC)anderer Takt als 610

Weil die Vorgänger-Jobs häufiger laufen als die abhängigen, ist die Vorarbeit in der Praxis immer schon erledigt — nur eben aus einem früheren Durchlauf, nicht aus demselben. Wer eine Reihenfolgeabhängigkeit prüft, sollte deshalb nicht allein auf die Ordnungsnummer schauen, sondern auch auf den Takt.

Die Operationen im Überblick

Sieben Operationen kommen in den Mappings vor. Sie sind das eigentliche Werkzeug der DataBridge — alles, was über eine reine Feld-zu-Feld-Zuordnung hinausgeht, ist eine dieser Operationen.

OperationRichtungWas sie tutWo sie vorkommt
LookupBC → CEmacht aus einem BC-Kürzel eine Dataverse-Verknüpfungüberall in den BC→CE-Mappings
LookupValueCE → BClöst eine Dataverse-Verknüpfung zum BC-Kürzel aufüberall in den CE→BC-Mappings
DefaultValuebeideschreibt einen festen Wert ohne QuellfeldFreigaben, Statuswerte, Kontaktarten, feste GUIDs
ReadFromMessageBC → CEliest einen Wert aus der Antwortnachricht statt aus einer Tabellealle vier Response-Jobs
OptionMappingBC → CEübersetzt einen BC-Textwert in einen Dataverse-Auswahlwertnur BCServiceCommitments
LinkToRecordCE → BCbaut aus der Datensatz-GUID einen aufrufbaren Deep Linknur CEOpportunities
SetNullIfEqualsValueOfFieldBC → CEParameter von Lookup: leert die Referenz bei Selbstbezugnur BCAccounts

Die letzten drei sind Einzelfälle — jede kommt in genau einem Mapping vor. Wer die Konfiguration erweitert, findet dort das jeweilige Muster.

Nächster Schritt

Die Feldzuordnungen der einzelnen Mappings sind in der Mapping-Übersicht gelistet. Die Detailseiten sind nach Datenbereich gegliedert: Stammdaten, Firma, Kontakt, Verkaufschance, Angebot und Abonnement.