Datenfluss
Themen:
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 (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 (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 (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 & Abos (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 (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 --> S5Muster 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 Job | Order | Response-Job | Order |
|---|---|---|---|
accountsnewfromce | 220 | accountsresponsefrombc | 221 |
contactsnewfromce | 240 | contactsresponsefrombc | 241 |
opportunitiesnewfromce | 260 | opportunitiesresponsefrombc | 261 |
opportunityproductsnewfromce | 710 | opportunityproductsresponsefrombc | 760 |
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 --> YDiese Jobs unterscheiden sich in zwei Punkten von den übrigen:
- Die Quelle ist immer
acdlogentries, nie die Fachtabelle. Der Filter grenzt übertableIddie betroffene BC-Tabelle ab, z. B.{{lastModifiedDateTime gt %watermark%}} and tableId eq 5050für Kontakte/Firmen. Als Schlüssel dientrecordId→wysa_bcsystemid. - Es gibt zwei Varianten, wie im Ziel reagiert wird:
| Variante | Jobs | Verhalten in CE |
|---|---|---|
Deaktivieren (kein Action-Feld) | accountsfrombcdelete, contactsfrombcdelete, productsfrombcdelete | Das 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) | salesquotesfrombcdelete | Das Mapping setzt statecode = 3 (Geschlossen) und statuscode = 6 (Storniert) — das Angebot bleibt erhalten |
Löschen (Action = Delete) | salescalculationelementsfrombcdelete | Die 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.
| Order | Job | Bereich | Takt |
|---|---|---|---|
| 110 | countriesfrombc | Stammdaten — Länder | 2 Min |
| 115 | languagesfrombc | Stammdaten — Sprachen | 2 Min |
| 120 | salutationsfrombc | Stammdaten — Anreden | 2 Min |
| 125 | customerdiscountgroupsfrombc | Stammdaten — Rabattgruppen | 2 Min |
| 130 | salespersonsfrombc | Stammdaten — Verkäufer | 2 Min |
| 135 | positionsfrombc | Stammdaten — Organisationsebenen | 2 Min |
| 190 | opportunityelementsfrombc | Verkaufschance — Kalkulationselemente | 2 Min |
| 220 | accountsnewfromce | Firma — neu nach BC | 2 Min |
| ↳ 221 | accountsresponsefrombc | Firma — Rückmeldung | nach 220 |
| 240 | contactsnewfromce | Kontakt — neu nach BC | 2 Min |
| ↳ 241 | contactsresponsefrombc | Kontakt — Rückmeldung | nach 240 |
| 260 | opportunitiesnewfromce | Verkaufschance — neu nach BC | 2 Min |
| ↳ 261 | opportunitiesresponsefrombc | Verkaufschance — Rückmeldung | nach 260 |
| 410 | accountsfrombc | Firma — aus BC | 2 Min |
| 420 | accountsfrombcdelete | Firma — Löschung | 2 Min |
| 430 | contactsfrombc | Kontakt — aus BC | 2 Min |
| 440 | contactsfrombcdelete | Kontakt — Löschung | 2 Min |
| 450 | productsfrombcdelete | Stammdaten — Produkte deaktivieren | 2 Min |
| 520 | accountupdatesfromce | Firma — Änderungen nach BC | 2 Min |
| 530 | contactupdatesfromce | Kontakt — Änderungen nach BC | 2 Min |
| 550 | serviceobjectsfrombc | Abonnement — Abonnements | 2 Min |
| 560 | servicecommitmentsfrombc | Abonnement — Zeilen | 2 Min |
| 610 | salesquotesfrombc | Angebot — Angebote aus BC | 2 Min |
| 620 | salescalculationelementsfrombc | Angebot — Positionen aus BC | 2 Min |
| 621 | salescalculationelementsfrombcdelete | Angebot — Positionen löschen | 2 Min |
| 625 | activatesalesquotesfrombc | Angebot — gewonnene Angebote | 3 Min |
| 690 | salesquotesfrombcdelete | Angebot — Angebote stornieren | 2 Min |
| 710 | opportunityproductsnewfromce | Verkaufschance — Positionen neu | 3 Min |
| 750 | opportunityproductsupdatesfromce | Verkaufschance — Positionen ändern | 3 Min |
| ↳ 760 | opportunityproductsresponsefrombc | Verkaufschance — Rückmeldung | nach 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"]
endDie 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:
| Job | Braucht Vorarbeit von | Konsequenz |
|---|---|---|
| 710 · Positionen neu nach BC | 190 (Kalkulationselemente) und 260 / 261 (Verkaufschance) | läuft in einem eigenen Tick — die Vorarbeit stammt aus einem früheren Durchlauf |
| 750 · Positionen ändern | 710, 760 | läuft im selben Tick wie 710, hier gilt die Ordnungsnummer |
| 625 · gewonnene Angebote | 610 (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.
Würde ein Job aus dem Zwei-Minuten-Takt in den Drei-Minuten-Takt verschoben (oder umgekehrt), ändert sich damit auch, ob seine Ordnungsnummer gegenüber anderen Jobs überhaupt noch wirkt. Ein Zeitplanwechsel ist also keine reine Performancefrage, sondern kann Reihenfolgeabhängigkeiten aufheben.
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.
| Operation | Richtung | Was sie tut | Wo sie vorkommt |
|---|---|---|---|
Lookup | BC → CE | macht aus einem BC-Kürzel eine Dataverse-Verknüpfung | überall in den BC→CE-Mappings |
LookupValue | CE → BC | löst eine Dataverse-Verknüpfung zum BC-Kürzel auf | überall in den CE→BC-Mappings |
DefaultValue | beide | schreibt einen festen Wert ohne Quellfeld | Freigaben, Statuswerte, Kontaktarten, feste GUIDs |
ReadFromMessage | BC → CE | liest einen Wert aus der Antwortnachricht statt aus einer Tabelle | alle vier Response-Jobs |
OptionMapping | BC → CE | übersetzt einen BC-Textwert in einen Dataverse-Auswahlwert | nur BCServiceCommitments |
LinkToRecord | CE → BC | baut aus der Datensatz-GUID einen aufrufbaren Deep Link | nur CEOpportunities |
SetNullIfEqualsValueOfField | BC → CE | Parameter von Lookup: leert die Referenz bei Selbstbezug | nur 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.