Das ist eine für den Ausdruck optimierte Ansicht des gesamten Kapitels inkl. Unterseiten. Druckvorgang starten.

Zur Standardansicht zurückkehren.

Konfiguration

Die vier Azure Tables als zentrales Konfigurationssystem: Verbindungen, Jobs, Mappings und Watermarks.

Die dsyr.DataBridge hat keine Konfigurationsdateien. Alle Laufzeit-Einstellungen — Verbindungen zu Quell- und Zielsystemen, Synchronisations-Jobs, Feld-Mappings und Änderungsstände — leben in vier Azure Tables innerhalb der zugehörigen Ressourcengruppe.

Das hat einen entscheidenden Vorteil: Anpassungen werden ohne Redeployment wirksam. Die Tabellen werden beim nächsten Funktionsaufruf automatisch neu eingelesen.

TabelleInhalt
connectionsZugangsdaten zu Quell- und Zielsystemen
jobsWelche Tabellen werden wann in welche Richtung synchronisiert
mappingsWelche Felder werden wie übertragen und transformiert
watermarksLetzter synchronisierter Stand pro Job

1 - Verbindungen (connections)

Die connections-Tabelle speichert Zugangsdaten zu allen Quell- und Zielsystemen.

Die Tabelle connections ist die Grundlage jeder DataBridge-Konfiguration. Sie enthält die Zugangsdaten zu allen Systemen, mit denen die DataBridge kommuniziert — sowohl Quell- als auch Zielsysteme.


Tabellenstruktur

SpalteWertBeschreibung
PartitionKeyconnectionMuss immer connection lauten
RowKeyfrei wählbarEindeutiger Name dieser Verbindung. Wird in der jobs-Tabelle als Referenz verwendet.
TimestampautomatischSystemseitig gesetzt, nicht bearbeitbar
TypeConnector-TypGibt an, um welches System es sich handelt (siehe Tabelle unten)
JsonJSON-ObjektSystem-spezifische Verbindungsparameter (unterscheidet sich je nach Type)

Unterstützte Connector-Typen

Type-WertSystemLesenSchreiben
D365BCDynamics 365 Business Central✅✅
D365CEDynamics 365 / Dataverse✅✅
D365NAVMicrosoft Dynamics NAV✅✅
MSSQLMicrosoft SQL Server⚠️ Preview—
MYSQLMySQL / MariaDB⚠️ Preview—
ORACLEOracle Database⚠️ Preview—
PGSQLPostgreSQL⚠️ Preview—
OPENAPIGenerische REST-API über OpenAPI-Spezifikation✅✅ (inkl. Löschen)

Universelle JSON-Parameter

Diese Parameter sind für alle Connector-Typen gültig und werden in das Json-Feld eingetragen. Alle sind optional:

ParameterStandardwertBeschreibung
keyVaultUrl(leer)URL zu einem Azure-Key-Vault-Secret. Wenn gesetzt, werden alle übrigen Parameter aus dem Secret geladen — das Json-Feld selbst enthält dann nur diesen einen Eintrag.
maxPageSize5000Maximale Anzahl Datensätze pro Abruf-Seite. Kann bei Performance-Problemen reduziert werden.
languagede-DEKultur für die Interpretation von Zahlen- und Datumsformaten.
httpClientTimeoutSeconds100Zeitlimit für einzelne Aufrufe in Sekunden. Relevant bei langsamen Quell- oder Zielsystemen.

Zusätzliche Parameter für HTTP-Konnektoren (D365BC, D365NAV, OpenAPI)

Diese Parameter stehen allen HTTP-basierten Konnektoren zur Verfügung, auch wenn sie bislang vor allem für den OpenAPI-Konnektor relevant sind:

ParameterStandardwertBeschreibung
apiKeyHeader(leer)Name des HTTP-Headers für API-Key-Authentifizierung (z. B. X-API-Key). Gesetzt ⇒ API-Key-Authentifizierung wird verwendet.
apiKeyValue(leer)Wert des API-Keys
tokenUrl(leer)Eigener OAuth2-Token-Endpunkt. Ohne Angabe wird weiterhin der Microsoft-Login-Endpunkt verwendet.
authmethod(leer)Erzwingt eine Authentifizierungsmethode: BasicAuthentication, OAuth2, APIKey oder ManagedIdentity (Groß-/Kleinschreibung egal). Ohne Angabe wird die Methode aus den vorhandenen Zugangsdaten abgeleitet. ManagedIdentity wird nie automatisch gewählt, sondern nur über diesen Parameter. Ein unbekannter Wert führt zu einem Fehler.

JSON-Parameter je Connector-Typ

D365BC — Business Central

Für Cloud-Umgebungen (OAuth2 Client Credentials):

{
  "clientId": "<App-Registration Client ID>",
  "clientSecret": "<App-Registration Client Secret>",
  "tenantId": "<Entra Tenant ID>",
  "environment": "<BC-Umgebungsname, z. B. production>",
  "companyId": "<BC Company ID (GUID)>"
}

Für OnPremise-Umgebungen (Basic Auth):

{
  "userName": "<domain\\benutzername>",
  "password": "<Passwort>",
  "url": "https://<server>:<port>/<pfad>"
}

Zusätzlicher optionaler Parameter:

ParameterStandardwertBeschreibung
scopehttps://api.businesscentral.dynamics.com/.defaultOAuth2-Scope beim Token-Abruf. Nur anzupassen, wenn ein abweichender Endpunkt genutzt wird.

Die Auswahl des Authentifizierungsverfahrens erfolgt automatisch: Sind userName und password gesetzt, verwendet die DataBridge Basic Auth, andernfalls OAuth2 Client Credentials aus clientId, clientSecret und tenantId.

D365CE — Dataverse / Customer Engagement

{
  "connectionstring": "<XRM-Connection-String>"
}

Alternativ über Managed Identity (ohne Secret):

{
  "url": "https://<org>.crm4.dynamics.com",
  "clientid": "<Client-ID der user-assigned Identity, optional>"
}

Ohne clientid wird die system-zugewiesene Identity verwendet. Ist connectionstring gesetzt, hat er immer Vorrang. Details siehe D365CE.

Das Format des XRM-Connection-Strings beschreibt die Microsoft-Dokumentation.

Beispiel:

AuthType=ClientSecret;Url=https://<org>.crm4.dynamics.com;ClientId=<id>;ClientSecret=<secret>

D365NAV — Microsoft Dynamics NAV

Für Cloud-Umgebungen (OAuth2 Client Credentials):

{
  "clientId": "<App-Registration Client ID>",
  "clientSecret": "<App-Registration Client Secret>",
  "tenantId": "<Entra Tenant ID>",
  "environment": "<NAV-Umgebungsname>",
  "companyId": "<Company ID (GUID)>"
}

Für OnPremise-Umgebungen:

{
  "userName": "<domain\\benutzername>",
  "password": "<Passwort>",
  "url": "https://<server>:<port>/<pfad>/",
  "baseAddress": "https://<server>:<port>/",
  "authenticationMethod": "NTLM"
}

Zusätzliche NAV-Parameter:

ParameterStandardwertBeschreibung
scopehttps://api.businesscentral.dynamics.com/.defaultOAuth2-Scope beim Token-Abruf
baseAddress(leer)Basis-Adresse für den NTLM-Credential-Cache. Nur bei authenticationMethod = NTLM relevant.
authenticationMethodBasicSiehe Hinweis unten

OPENAPI — generischer REST-Konnektor

{
  "baseUrl": "https://api.example.com",
  "openApiSpecUrl": "https://api.example.com/openapi.yaml",
  "clientId": "<Client-ID>",
  "clientSecret": "<Client-Secret>",
  "tenantId": "<Entra Tenant ID>",
  "tokenUrl": "https://api.example.com/oauth/token",
  "apiKeyHeader": "X-API-Key",
  "apiKeyValue": "<API-Key>",
  "customHeaders": { "X-Custom-Header": "wert" }
}

Vollständige Parameterliste, Authentifizierungsauswahl, Paginierung und Besonderheiten: Konnektoren → OpenAPI.

SQL-Datenbanken (MSSQL, MYSQL, ORACLE, PGSQL)

Alle SQL-Konnektoren verwenden einen einzelnen Connection String:

{
  "connectionstring": "<datenbankspezifischer Connection String>"
}

Zusätzlicher optionaler Parameter:

ParameterStandardwertBeschreibung
commandTimeOut30Zeitlimit für einzelne SQL-Befehle in Sekunden. Bei großen Tabellen oder langsamen Abfragen zu erhöhen.

Diagnose-Schalter (D365BC und D365NAV)

Für die Fehlersuche lassen sich zusätzliche Protokollierungen einschalten. Alle drei Schalter stehen standardmäßig auf false:

ParameterBeschreibung
logCreateRequestsProtokolliert die vollständigen Anfragen beim Anlegen von Datensätzen
logUpdateRequestsProtokolliert die vollständigen Anfragen beim Aktualisieren von Datensätzen
logReceivedDataProtokolliert die vollständigen Antwortdaten des Systems

Key Vault — Verbindungsdaten sicher speichern

Statt Credentials direkt in Table Storage zu speichern, kann ein Azure-Key-Vault-Secret referenziert werden. Das Json-Feld enthält dann nur die Referenz:

{
  "keyVaultUrl": "https://<vault>.vault.azure.net/secrets/<secret-name>/"
}

Das Secret selbst enthält das vollständige JSON-Objekt der Verbindung — also alle Parameter, die sonst direkt im Json-Feld stünden. Beim Verbindungsaufbau lädt die DataBridge das Secret und ersetzt damit die gesamte Verbindungskonfiguration.

Optional lässt sich eine bestimmte Secret-Version adressieren, indem die Versions-ID an den Pfad angehängt wird.


Hinweise

  • Der RowKey ist der Bezeichner, der in der jobs-Tabelle unter SourceConnection bzw. TargetConnection eingetragen wird. Sprechende Namen wählen (z. B. bc-produktion, dataverse-test).
  • Eine Verbindung kann von mehreren Jobs gleichzeitig genutzt werden.
  • Beim Start prüft die DataBridge jede Verbindung mit einem Verbindungstest. Schlägt er fehl, bricht der laufende Aufruf ab und die Initialisierung wird beim nächsten Aufruf erneut versucht.
  • Änderungen in der connections-Tabelle werden bei der nächsten Initialisierung eingelesen — kein Redeployment nötig.

2 - Jobs (jobs)

Die jobs-Tabelle definiert, welche Daten wann und in welche Richtung synchronisiert werden.

Ein Job beschreibt genau eine Synchronisationsrichtung zwischen zwei Systemen: er verbindet eine Quelltabelle mit einer Zieltabelle, legt den Zeitplan fest und verweist auf das zugehörige Mapping.


Tabellenstruktur

SpaltePflichtBeschreibung
PartitionKey✅Muss immer job lauten.
RowKey✅Eindeutiger Jobname. Wird im Logging und als Referenz für ResponseJobs verwendet.
IsActive✅true = Job wird von GetChanges ausgeführt. false = Job wird nur indirekt (als ResponseJob) aufgerufen.
SourceConnection✅RowKey-Referenz auf einen Eintrag in der connections-Tabelle (Quelldaten).
TargetConnection✅RowKey-Referenz auf einen Eintrag in der connections-Tabelle (Zieldaten).
Mapping✅PartitionKey-Referenz auf eine Gruppe von Einträgen in der mappings-Tabelle.
Source—Quellressource (Tabelle, Entität, Pfad oder Aktion). Überschreibt die SourceTable der Mapping-Zeilen für diesen Job (siehe unten).
Target—Zielressource (Tabelle, Entität, Pfad oder Aktion). Überschreibt die TargetTable der Mapping-Zeilen für diesen Job (siehe unten).
Order✅Ganzzahl. Legt die Ausführungsreihenfolge fest — muss über alle Jobs eindeutig sein.
WatermarkField—Feldname im Quellsystem, der als Änderungsindikator genutzt wird (meistens ein Datums-/Zeitstempelfeld). Nur bei WatermarkType = date oder datetime erforderlich; bei string (Dataverse Change Tracking) bleibt das Feld leer.
WatermarkType✅Typ des Watermark-Wertes: date, datetime oder string (Details: Watermarks).
Filter—Filterausdruck für die Quellanfrage. Format ist systemabhängig (siehe unten).
Schedule—CRON-Ausdruck (6-stellig, NCrontab). Wenn leer, läuft der Job bei jedem Timer-Aufruf.
Action—Steuert, welche Änderungsarten gelesen werden, oder benennt eine Aktion. Leer = NewUpdate. Wirkt bei den CRUD-Werten (Delete, DeleteOnUpdate) nur bei D365CE als Quellsystem (siehe unten); ein nicht erkannter Wert schaltet den Job auf InvokeAction (siehe unten).
Priority—Standard (Vorgabe), High oder Low. Steuert die Service-Bus-Queue.
ResponseJob—RowKey eines anderen Jobs, der nach erfolgreichem Schreiben automatisch ausgeführt wird.
IsValid—Reserviert. Die Spalte kommt in bestehenden Tabellen vor, wird von der DataBridge aber nicht gelesen und hat keine Wirkung.

Ausführungsreihenfolge

Das Feld Order bestimmt, in welcher Reihenfolge die fälligen Jobs bei jedem Timer-Aufruf abgearbeitet werden. Empfehlung: BC-Jobs vor CE-Jobs ausführen, um sicherzustellen, dass IDs aus BC schon in Dataverse existieren, bevor sie referenziert werden.

Order 10: BC → CE (Stammdaten, z. B. Kunden)
Order 20: BC → CE (Bewegungsdaten, z. B. Angebote)
Order 30: CE → BC (Rückmeldungen)

Der Order-Wert muss über alle Jobs eindeutig sein — auch über inaktive ResponseJobs hinweg. Ein doppelter Wert führt dazu, dass die betroffenen Jobs als unvollständig markiert und nicht ausgeführt werden.


Filter-Syntax

Der Filter bestimmt, welche Datensätze aus der Quelle abgerufen werden.

D365BC, D365NAV und SQL — Filter mit Watermark-Platzhalter

Der Filterausdruck wird als Bedingung in die Quellanfrage eingesetzt. Zwei Elemente steuern das Verhalten:

  • %watermark% wird zur Laufzeit durch den gespeicherten Watermark-Wert ersetzt
  • {{ … }} klammert einen Block, der komplett entfällt, wenn die Watermark leer ist
{{lastModifiedDateTime gt %watermark%}}

Ist die Watermark leer (Erstlauf oder manuell geleert), verschwindet der gesamte Block und der Job liest den vollständigen Bestand. Genau dafür ist die Klammerung gedacht.

Richtig kombiniert wird, indem die Zusatzbedingung außerhalb der Klammer steht und das and mit in den Watermark-Block wandert:

blocked eq false {{and lastModifiedDateTime gt %watermark%}}
WatermarkErgebnis
gesetztblocked eq false and lastModifiedDateTime gt 2026-08-01T10:00:00.000Z
leerblocked eq false

Beide Varianten sind gültig — der Erstlauf liest den vollen Bestand, gefiltert auf blocked eq false.

D365CE / Dataverse — JSON-Operationen

Dataverse nutzt die Change Tracking API; ein OData-Filter kommt dort nicht zum Einsatz. Stattdessen erwartet das Filter-Feld ein JSON-Objekt, das nach dem Abruf clientseitig ausgewertet wird — passende Datensätze werden verarbeitet, alle anderen verworfen.

{ "Operations": [ { "Name": "NotNull", "Parameters": { "SourceField": "wysa_number" } } ] }
{ "Operations": [ { "Name": "StatusCode", "Parameters": { "Value": 3 } } ] }
OperationParameterWirkung
EqualsSourceField, ValueFeldwert entspricht dem angegebenen Wert
BooleanSourceField, ValueBoolesches Feld entspricht dem angegebenen Wert
OptionSetValueSourceField, ValueOptionsset-Feld entspricht dem angegebenen Wert
NotNullSourceFieldFeld ist gefüllt
IsNullSourceFieldFeld ist leer
StatusCodeValueDatensatz hat den angegebenen Statuscode

Ein nicht aufgeführter Operationsname führt zu einem Fehler (Undefined FilterOperation). Die unter SourceField genannten Felder werden automatisch mit abgefragt — sie müssen nicht zusätzlich im Mapping stehen.


Schedule — jobbezogener CRON-Ausdruck

Wenn ein Job seltener als der globale Timer laufen soll, kann ein eigener CRON-Ausdruck eingetragen werden. Die DataBridge prüft anhand von LastCronRun im Watermark, ob das Intervall bereits abgelaufen ist.

Beispiele:

ScheduleBedeutung
0 */2 * * * *Alle 2 Minuten
0 */15 * * * *Alle 15 Minuten
0 0 * * * *Stündlich
0 0 6 * * *Täglich um 06:00 Uhr
(leer)Greift bei jedem Timer-Aufruf

Der globale Timer (GetChangesTimerExpression) steht bei einer Neuinstallation auf */15 * * * * * — also alle 15 Sekunden. Ein Job ohne eigenen Schedule wird damit bei jedem dieser Läufe geprüft.


Priorität

WertService-Bus-QueueTypischer Einsatz
HighsbqhighexportZeitkritische Stammdaten (Preise, Kundenstatus)
StandardsbqexportNormalbetrieb (Vorgabe, auch bei leerem oder unbekanntem Wert)
LowsbqlowexportGroße Historien-Importe, Bulk-Daten

Jede der drei Queues hat einen eigenen, gleichrangigen Verarbeiter. Sie laufen unabhängig und parallel — dadurch bleibt eine hochpriore Nachricht nicht hinter einem Rückstau niedrigerer Priorität stehen. Eine echte Vorrang-Reihenfolge zwischen den Queues gibt es nicht.


Action — welche Änderungsarten gelesen werden

WertWirkung
(leer) / NewUpdateNur Neuanlagen und Änderungen (Vorgabe, auch bei unbekanntem Wert)
DeleteNur Löschungen
DeleteOnUpdateLöschungen, die im Quellsystem als Änderung auftreten
AllNeuanlagen, Änderungen und Löschungen in einem Job
ein beliebiger anderer WertDer Job wird als Aktions-Job (InvokeAction) behandelt — siehe unten

InvokeAction — Aktions-Jobs

(neu) Enthält Action weder einen leeren Wert noch den Namen eines bekannten JobActionType (NewUpdate, Delete, TimeStamp, DeleteOnUpdate), wird der Job zu einem Aktions-Job: Statt eines CRUD-Zyklus ruft er einen benannten, nicht-CRUD-Endpunkt auf. Der Wert von Action wird dabei unverändert als Aktionsname übernommen — z. B. ein OpenAPI-operationId oder der Name eines CE-OrganizationRequest.

Action = SendByEInvoice

Aktuell implementiert der OpenAPI-Konnektor InvokeAction (ResourcePath aus Source/Target bzw. TargetPath + TargetTable der Mapping-Zeilen). Details und Konfigurationsbeispiel: Konnektoren → OpenAPI → InvokeAction.


Source und Target — job-eigene Ressourcenpfade

(neu) Bislang bestimmten ausschließlich die Mapping-Zeilen (SourceTable/TargetTable), welche Ressource ein Job liest bzw. beschreibt. Ein Job kann jetzt zusätzlich eigene Felder Source und Target tragen, die diese Werte überschreiben:

  • Sind Source/Target am Job leer, gilt weiterhin das bisherige Verhalten — die Mapping-Zeilen bestimmen die Ressource (mit einer einmaligen Warnung im Log, die auf die ältere Konfigurationsform hinweist).
  • Ist mindestens eines der beiden Felder gesetzt, wird nur dieses überschrieben; das jeweils andere fällt weiterhin auf den Mapping-Wert zurück.
  • Fehlt sogar das Mapping-Feld am Job komplett, wird aus Source/Target ein synthetisches Mapping ohne TargetKey erzeugt (JOB-<Jobname>) — nützlich für reine Aktions-Jobs ohne Feld-Mapping.
  • Enthält Source/Target einen Schrägstrich (pfad/ressource), wird der Teil vor dem letzten Schrägstrich als Pfad (SourcePath/TargetPath), der Teil danach als Ressourcenname (SourceTable/TargetTable) interpretiert.
Source = v2/clients
Target = v2/client_invoices/{id}/send_by_einvoice

Damit lässt sich ein und dieselbe Mapping-Definition für mehrere Ressourcen bzw. Aktionspfade wiederverwenden, statt für jede Kombination eine eigene Mapping-Gruppe anzulegen.


ResponseJob — Rückschreiben von IDs

Ein ResponseJob löst das Problem, dass Business Central beim Anlegen eines Datensatzes eine neue interne ID vergibt, die anschließend in Dataverse gespeichert werden soll.

Ablauf:

  1. Job A schreibt einen Datensatz von CE nach BC
  2. BC antwortet mit dem neu erzeugten Datensatz inkl. der neuen BC-ID
  3. Die DataBridge führt automatisch Job B (den ResponseJob) aus
  4. Job B liest die BC-ID aus der Antwort (ReadFromMessage-Operation) und schreibt sie zurück nach CE

Konfiguration:

Job A:  IsActive = true
        ResponseJob = "JobB-RowKey"

Job B:  IsActive = false   ← wird nur durch Job A ausgelöst, nie direkt
        SourceConnection = BC-Verbindung
        TargetConnection = CE-Verbindung

Felder, die aus der BC-Antwort gelesen werden, werden im Mapping mit einem Unterstrich-Präfix im SourceField markiert und die Operation ReadFromMessage eingetragen (Details: Mappings → ReadFromMessage).

3 - Mappings (mappings)

Die mappings-Tabelle definiert, welche Felder wie zwischen Quell- und Zielsystem übertragen und transformiert werden.

Die mappings-Tabelle ist die mächtigste Konfigurationsebene der DataBridge. Sie legt für jedes Feld fest: woher kommt der Wert, wohin geht er, und wie wird er unterwegs transformiert.

Ein Mapping ist eine Gruppe von Zeilen in der Tabelle — alle mit demselben PartitionKey. Jede Zeile beschreibt genau eine Feld-Zuordnung.


Tabellenstruktur

SpaltePflichtBeschreibung
PartitionKey✅Name des Mappings. Wird im Job unter Mapping referenziert. Im Gegensatz zu jobs und connections ist der PartitionKey hier frei wählbar — er dient der Gruppierung.
RowKey✅Eindeutiger Bezeichner innerhalb des Mappings. Konvention: _quellfeld__zielfeld_
SourceTable✅Name der Quelltabelle/-entität. Muss innerhalb eines Mappings konsistent sein.
SourceField—Name des Quellfeldes. Kann leer sein (bei DefaultValue) oder mit _ beginnen — dann handelt es sich um ein virtuelles Feld.
TargetTable✅Name der Zieltabelle/-entität. Muss innerhalb eines Mappings konsistent sein.
TargetField✅Name des Zielfeldes. Muss dem tatsächlichen API-/Spaltenname entsprechen.
TargetKey—JSON-Objekt. Definiert, wie ein bestehender Datensatz im Zielsystem identifiziert wird (für Upsert-Logik).
SourceOperation—JSON-Objekt der Form { "Operations": [ … ] }. Transformation beim Lesen aus der Quelle.
TargetOperation—JSON-Objekt der Form { "Operations": [ … ] }. Transformationen beim Schreiben ins Ziel.

RowKey-Namenskonvention

Die empfohlene Konvention für den RowKey: _quellfeld__zielfeld_

Beispiele:

_systemid__wysa_bcsystemid_
_lastModifiedDateTime__wysa_lastmodified_
_no__wysa_bcnumber_

Doppelter Unterstrich trennt Quell- vom Zielfeld. Die umgebenden Unterstriche kennzeichnen es als Mapping-RowKey. Diese Konvention ist optional, aber empfohlen für Lesbarkeit und Filterbarkeit.


TargetKey — Upsert-Schlüssel

Der TargetKey bestimmt, wie die DataBridge entscheidet, ob ein Datensatz im Zielsystem angelegt (Insert) oder aktualisiert (Update) wird.

Es gibt vier Typen:

PrimaryKey

Nutzt den systemnativen Primärschlüssel des Zielsystems. Der Schlüsselname wird automatisch aus dem SourceField der Mapping-Zeile übernommen.

{ "KeyType": "PrimaryKey" }

Id

Ähnlich wie PrimaryKey, nutzt jedoch die systemspezifische ID-Eigenschaft des Connectors.

{ "KeyType": "Id" }

CustomKey

Benutzerdefinierter Schlüssel aus einem oder mehreren Feldern. Wird eingesetzt, wenn der Datensatz im Zielsystem nicht über den Primärschlüssel, sondern über eine Geschäftsfeld-Kombination identifiziert wird.

{
  "KeyType": "CustomKey",
  "KeyName": "wysa_number",
  "KeyValues": [
    { "keyName": "wysa_segmentno", "attributeName": "segmentNo", "rank": 1 },
    { "keyName": "wysa_lineno",    "attributeName": "lineNo",    "rank": 2 }
  ]
}
FeldBedeutung bei CustomKey
KeyNameZielfeld, das den zusammengesetzten Schlüsselwert enthält
keyNameZielfeld-Name für diesen Schlüsselteil
attributeNameQuellfeld-Name, aus dem der Wert kommt
StaticValueFester Wert statt eines Quellwertes (siehe unten)
rankReihenfolge der Schlüsselteile innerhalb des Schlüssels (aufsteigend)

Filter

Sucht im Zielsystem nach einem Datensatz, der alle angegebenen Feld-Wert-Kombinationen erfüllt. Im Gegensatz zu CustomKey wird kein explizites Schlüsselfeld benötigt.

{
  "KeyType": "Filter",
  "KeyValues": [
    { "keyName": "mailingGroupCode", "attributeName": "listid",   "rank": 1 },
    { "keyName": "contactNo",        "attributeName": "entityid", "rank": 2 }
  ]
}

Statische Schlüsselwerte

(ab v2.1 — verfügbar für D365CE und D365BC)

Ein Schlüsselteil kann gegen einen fest hinterlegten Wert aufgelöst werden, ohne dass dafür ein Quellfeld existieren muss. Dazu wird statt attributeName das Feld StaticValue gesetzt:

{
  "KeyType": "CustomKey",
  "KeyName": "wysa_category",
  "KeyValues": [
    { "keyName": "wysa_category", "StaticValue": "STANDARD", "rank": 1 }
  ]
}

StaticValue greift nur, wenn attributeName leer ist. Ist beides gesetzt, gewinnt der Quellwert.

Bei Business Central werden statische Werte für die Metadaten-Typen string, guid und int32 unterstützt; andere Typen führen zu einem Fehler.

Mehrere Ziel-Schlüssel mit Rangfolge

(ab v2.1)

Ein Mapping kann mehrere Ziel-Schlüssel besitzen. Sie werden anhand des Feldes KeyRank in aufsteigender Reihenfolge geprüft — sobald ein Schlüssel im Zielsystem einen Datensatz findet, wird dieser verwendet und die übrigen werden übersprungen.

Typischer Einsatz: zuerst über eine externe ID suchen, ersatzweise über eine Nummer.

Die Konfiguration unterscheidet sich je nach Ebene:

EbeneVorgehen
Table-MappingJe Schlüssel eine eigene Mapping-Zeile mit eigenem TargetKey-JSON anlegen. Die DataBridge fasst alle TargetKey-Einträge einer Mapping-Gruppe zusammen und sortiert sie nach KeyRank.
Lookup (TargetOperation)In Parameters statt TargetKey ein Array TargetKeys mit mehreren Schlüsseln angeben.
{
  "KeyType": "CustomKey",
  "KeyRank": 1,
  "KeyName": "wysa_externalid",
  "KeyValues": [
    { "keyName": "wysa_externalid", "attributeName": "externalId", "rank": 1 }
  ]
}

Bestehende Mappings mit einem einzelnen TargetKey funktionieren unverändert — intern wird ein einzelner Schlüssel wie eine Liste mit einem Eintrag behandelt.

KeyAttributeFromExisting

Optionales Feld am TargetKey, ausgewertet bei KeyType: Filter von den Konnektoren für Business Central, NAV und OpenAPI. Der Filter findet nur den bestehenden Zieldatensatz. Für die Item-URL beim Aktualisieren (bei OpenAPI auch beim Löschen) wird der Schlüssel aus dem hier angegebenen Feld dieses Datensatzes übernommen.

  • BC/NAV: Pflicht bei Filter. Guid- und Zahl-Schlüssel werden ohne, alle anderen mit Hochkommas in die URL geschrieben, der Typ kommt aus den Metadaten. Fehlt das Feld im bestehenden Datensatz, bricht die Verarbeitung mit einem Fehler ab.
  • OpenAPI: Optional. Ohne Angabe wird der Primärschlüssel der Spezifikation verwendet (id, Id, ID, uuid oder key).

Der Feldname ist case-sensitiv (id ≠ Id).

IgnoreEmptySourceKey

(ab v2.2, nur D365CE)

Optionales Boolesches Feld am TargetKey. Standard ist false.

{
  "KeyType": "CustomKey",
  "KeyRank": 2,
  "KeyName": "wysa_externalid",
  "IgnoreEmptySourceKey": true,
  "KeyValues": [
    { "keyName": "wysa_externalid", "attributeName": "externalId", "rank": 1 }
  ]
}

Zwei verschiedene Arten von „kein Treffer"

Um das Feld einordnen zu können, muss man zwei Situationen auseinanderhalten, die beide danach aussehen, als wäre ein Schlüssel erfolglos geblieben:

SituationWas passiertVerhalten ohne dieses Feld
Schlüssel lässt sich nicht aufbauen — das Quellfeld ist leer, es gibt gar keinen Wert zum SuchenEs wird nicht gesuchtFehler, die Nachricht schlägt fehl
Schlüssel findet nichts — es wurde gesucht, im Zielsystem existiert der Datensatz noch nichtSuche läuft, bleibt ergebnislosDatensatz wird angelegt — kein Fehler

Die zweite Zeile ist der Normalfall für jeden neuen Datensatz: Beim ersten Übertragen findet kein Schlüssel etwas, und genau deshalb wird angelegt. IgnoreEmptySourceKey ändert daran nichts.

Das Feld wirkt ausschliesslich auf die erste Zeile: Es erklärt einen leeren Quellwert für diesen einen Schlüssel zum Normalfall statt zum Fehler.

Wann das Feld überhaupt zum Tragen kommt

Die Schlüssel werden nach KeyRank der Reihe nach geprüft. Sobald ein Schlüssel einen Datensatz findet, bricht die Suche ab und der Datensatz wird aktualisiert — unabhängig davon, was bei den vorherigen Schlüsseln passiert ist und wie sie konfiguriert sind.

Beispiel mit drei Schlüsseln, bei dem Schlüssel 1 leer und nicht markiert ist:

SchrittErgebnis
Schlüssel 1leer, wird übersprungen — gemerkt: „hier war ein Fehler"
Schlüssel 2leer, markiert — wird übersprungen
Schlüssel 3findet den Datensatz → Suche endet
ErgebnisUpdate. Kein Fehler — der gemerkte Fehler wird gar nicht mehr ausgewertet

Das Feld greift also nur dann, wenn die Liste vollständig durchlaufen wurde und kein einziger Schlüssel einen Datensatz gefunden hat. Erst dann steht die Frage „Fehler oder anlegen?" überhaupt im Raum.

Die Entscheidung am Ende

Hat kein Schlüssel etwas gefunden, entscheidet sich Folgendes:

  • Waren alle leer gebliebenen Schlüssel mit IgnoreEmptySourceKey: true markiert (oder blieb gar keiner leer), wird ein neuer Datensatz angelegt.
  • War auch nur einer der leer gebliebenen Schlüssel nicht markiert, bleibt es beim Fehler.

Das Feld gilt also je Schlüssel: Es hebt die Fehlerbehandlung der übrigen Schlüssel nicht auf. Lassen Sie es bei einem Schlüssel bewusst weg, bleibt ein leerer Wert dort ein Fehler — auch wenn ein anderer Schlüssel des Mappings markiert ist.

Typischer Einsatz

Ein optionales Feld wie eine externe ID ist nicht in jedem Quelldatensatz gefüllt, die Belegnummer dagegen immer. Mit IgnoreEmptySourceKey: true am ID-Schlüssel laufen auch die Datensätze ohne externe ID sauber durch und werden über die Belegnummer gefunden.

Das Feld wird derzeit ausschliesslich vom D365CE-Konnektor ausgewertet. Bei Business Central und NAV bleibt es wirkungslos.


Virtuelle Felder

Beginnt das SourceField mit einem Unterstrich, handelt es sich um ein virtuelles Feld: Es wird nicht aus der Quelltabelle gelesen, sondern zur Laufzeit über eine SourceOperation erzeugt.

Der ResponseJob ist dabei nur einer von mehreren Anwendungsfällen:

AnwendungsfallOperation
Wert aus einer anderen Tabelle nachschlagenLookupValue
Wert aus einer ActivityParty-Beziehung lesenActivityParty
Link auf einen Dataverse-Datensatz erzeugenLinkToRecord
Wert aus der Antwortnachricht lesen (ResponseJob)ReadFromMessage
Zeilen eines Kind-Jobs einbettenEmbedChildren

SourceOperation — Transformation beim Lesen

SourceOperations werden angewendet, bevor der Wert in die Service Bus Queue geschrieben wird. Sie sind connector-spezifisch — nicht jede Operation steht in jedem Connector zur Verfügung.

LookupValue

(verfügbar: D365BC, D365CE, D365NAV)

Liest einen Wert aus einer anderen Tabelle im Quellsystem nach. Beispiel: Aus einem Land-Code soll der ausgeschriebene Ländername übertragen werden.

{
  "Operations": [
    {
      "Name": "LookupValue",
      "Parameters": {
        "LookupType": "Attribute",
        "SourceField": "countryRegionCode",
        "LookupTable": "publisher/product/v1.0/countriesRegions",
        "LookupField": "name",
        "UseCache": true
      }
    }
  ]
}
ParameterBeschreibung
LookupTypeAttribute — liest ein bestimmtes Feld aus dem gefundenen Datensatz. Name — liefert den Anzeigenamen des verknüpften Datensatzes; dann entfallen LookupTable und LookupField.
SourceFieldFeld im Quelldatensatz, das den Suchwert enthält
LookupTableAPI-Pfad der nachzuschlagenden Tabelle
LookupFieldFeld im nachgeschlagenen Datensatz, dessen Wert übertragen wird
UseCachetrue dringend empfohlen — siehe Hinweis

ReadFromMessage

(verfügbar: D365BC, D365NAV, D365CE)

Liest einen Wert aus der ursprünglichen Queue-Nachricht — wird typischerweise in ResponseJobs verwendet, um Felder aus der Antwort des Zielsystems (z. B. eine neu vergebene ID) zurückzuschreiben.

{
  "Operations": [
    { "Name": "ReadFromMessage" }
  ]
}

Zugehörige Zeile in der Tabelle:

SpalteWert
SourceField_id (Unterstrich-Präfix!)
TargetFieldwysa_bcid

ActivityParty

(verfügbar: nur D365CE)

Liest ein Feld über eine ActivityParty-Beziehung aus. Wird für CE-Aktivitäten (E-Mails, Aufgaben) verwendet, bei denen Teilnehmer über den activityparty-Datensatz verknüpft sind.

{
  "Operations": [
    {
      "Name": "ActivityParty",
      "Parameters": {
        "PartyParams": {
          "TypeMask": 2,
          "SourceField": "activityid",
          "TargetField": "wysa_number",
          "TargetTable": "contact"
        }
      }
    }
  ]
}
ParameterBeschreibung
TypeMaskTeilnehmertyp (siehe Hinweis)
SourceFieldFeld mit der Activity-ID
TargetFieldFeld im verknüpften Datensatz, das gelesen werden soll
TargetTableEntität des verknüpften Datensatzes

Werden mehrere Teilnehmer gefunden, werden ihre Werte komma-separiert zusammengefügt.

LinkToRecord

(verfügbar: nur D365CE)

Erzeugt eine anklickbare URL zu einem Datensatz in Dataverse. Nützlich, um in BC oder SQL einen direkten Link auf den zugehörigen CE-Datensatz zu speichern.

{
  "Operations": [
    {
      "Name": "LinkToRecord",
      "Parameters": {
        "BaseUrl": "https://<org>.crm4.dynamics.com/main.aspx?appid=<AppId>&pagetype=entityrecord"
      }
    }
  ]
}

An die angegebene Basis-URL werden automatisch &etn=<entity> und &id=<guid> angehängt.

EmbedChildren

(neu, verfügbar: nur D365CE als Quellsystem)

Bettet die Zeilen eines referenzierten Kind-Jobs in die Nachricht des Elterndatensatzes ein, sodass Eltern- und Kind-Datensätze gemeinsam als eine Nachricht durch den Service Bus laufen und gemeinsam ins Ziel geschrieben werden — z. B. eine Rechnung mit ihren Rechnungspositionen.

{
  "Operations": [
    {
      "Name": "EmbedChildren",
      "Parameters": { "JobName": "invoice-lines" }
    }
  ]
}

Zugehörige Zeile in der Tabelle:

SpalteWert
SourceField_lines (Unterstrich-Präfix, beliebiger Name)
TargetFieldPfad im Zieldatensatz, unter dem das Array landet (z. B. lines)

Der referenzierte Kind-Job liefert SourceConnection, Quellressource und Mapping; sein Filter kann {{...%parent.feld%...}}-Platzhalter enthalten, die zur Abrufzeit gegen den Eltern-Quelldatensatz aufgelöst werden. Beim Schreiben in eine OpenAPI-Zielressource wird daraus ein verschachteltes JSON-Array gebaut und unverändert — ohne Feld-für-Feld-Abgleich gegen ein eventuell vorhandenes Zielarray — mit der Elternanfrage übertragen.


TargetOperation — Transformationen beim Schreiben

TargetOperations werden angewendet, bevor der Wert ins Zielsystem geschrieben wird.

DefaultValue

(alle Konnektoren)

Schreibt immer einen festen Wert ins Zielfeld — unabhängig vom Quellwert. Das SourceField kann in diesem Fall leer gelassen werden.

{
  "Operations": [
    { "Name": "DefaultValue", "Parameters": { "DefaultValue": "2" } }
  ]
}

DefaultValueIfNullOrEmpty

(alle Konnektoren)

Schreibt einen festen Wert nur dann, wenn das Quellfeld leer oder null ist. Ist ein Quellwert vorhanden, wird dieser unverändert verwendet.

{
  "Operations": [
    { "Name": "DefaultValueIfNullOrEmpty", "Parameters": { "DefaultValue": "unbekannt" } }
  ]
}

DefaultValueMap

(alle Konnektoren)

Übersetzt den ermittelten Wert anhand einer Zuordnungsliste. Der Schlüsselvergleich erfolgt ohne Beachtung der Groß-/Kleinschreibung.

{
  "Operations": [
    {
      "Name": "DefaultValueMap",
      "Parameters": {
        "Mapping": [
          { "Key": "DE", "Value": "Deutschland" },
          { "Key": "AT", "Value": "Österreich" }
        ]
      }
    }
  ]
}

Findet sich kein passender Schlüssel, bleibt der Wert unverändert — im Unterschied zu OptionMapping, das in diesem Fall einen Fehler wirft.

Lookup

(nur D365CE)

Befüllt ein Lookup-Feld in Dataverse, indem der verknüpfte Datensatz über einen Schlüssel gesucht wird.

{
  "Operations": [
    {
      "Name": "Lookup",
      "Parameters": {
        "TargetTable": "contact",
        "TargetKey": {
          "KeyType": "CustomKey",
          "KeyName": "wysa_number",
          "KeyValues": [
            { "keyName": "wysa_number", "attributeName": "contactNo", "rank": 1 }
          ]
        }
      }
    }
  ]
}

TargetTable ist zwingend — ohne diesen Parameter bricht die Auflösung ab.

ParameterBeschreibung
TargetTableEntität des zu suchenden Datensatzes (Pflicht)
TargetKeyEinzelner Schlüssel, Syntax wie beim TargetKey
TargetKeysArray mehrerer Schlüssel mit KeyRank (ab v2.1, siehe oben)
DoNotCreatetrue verhindert das automatische Anlegen (ab v2.1, siehe unten)
SetNullIfEqualsValueOfFieldSetzt das Lookup auf null, wenn der Wert dem angegebenen Feld der Nachricht entspricht — Schutz gegen Selbstreferenzen
DefaultValueFester Wert; überspringt die Auflösung vollständig

OptionMapping

(verfügbar: D365CE; bei D365BC und D365NAV für String-Felder)

Übersetzt Textwerte aus dem Quellsystem in numerische Optionset-Werte von Dataverse (und umgekehrt). Die Mapping-Liste enthält alle bekannten Schlüssel-Wert-Paare.

{
  "Operations": [
    {
      "Name": "OptionMapping",
      "Parameters": {
        "Mapping": [
          { "Key": "Blank",                       "Value": "" },
          { "Key": "Prospect",                    "Value": "383380000" },
          { "Key": "First_x002D_time_x0020_Donor","Value": "383380001" },
          { "Key": "Recurring_x0020_Donor",       "Value": "383380002" }
        ]
      }
    }
  ]
}

Für MultiSelect-Optionsets ist zusätzlich der Parameter OptionDelimiter anzugeben — er trennt die Einzelwerte im Quellstring. Ohne ihn schlägt die Aufteilung fehl.


Datentyp-Umwandlung

Welche Quelltypen ein Zielfeld akzeptiert, hängt vom Connector und vom Zielfeld-Typ ab. Die vollständigen Matrizen stehen auf den Konnektor-Seiten.

Zwei Punkte, die häufig zu Rückfragen führen:

String zu Dezimalzahl (ab v2.1) — Dezimalfelder akzeptieren jetzt auch Quellwerte vom Typ string. Diese werden immer im Format en-US interpretiert, also mit Punkt als Dezimaltrennzeichen. Ein leerer String wird zu null, ein nicht konvertierbarer Wert erzeugt einen Fehler.

Culture bei echten Zahlentypen — kommt der Wert dagegen bereits als decimal oder money, gilt die im Verbindungs-JSON eingestellte language (Vorgabe de-DE).


Spezialfälle

Feld ohne Quellwert (reiner Standardwert)

Soll ein Zielfeld immer mit einem festen Wert befüllt werden, ohne dass ein Quellfeld existiert:

SpalteWert
SourceField(leer)
TargetFieldwysa_datasource
TargetOperationDefaultValue mit "DefaultValue": "DataBridge"

Wert aus der Antwortnachricht lesen (ResponseJob)

SpalteWert
SourceField_id
TargetFieldwysa_bcid
SourceOperationReadFromMessage

Siehe auch Virtuelle Felder und Jobs → ResponseJob.

Mehrere Operationen in einer Zeile

Ob mehrere Einträge im Operations-Array wirken, hängt davon ab, um welche Art von Operation es sich handelt:

Verhalten bei mehreren Einträgen
SourceOperationNur der erste Eintrag wird ausgeführt, alle weiteren verworfen
TargetOperationMehrere Einträge sind zulässig; sie werden über ihren Namen aufgelöst, nicht über die Reihenfolge. Es gilt die Rangfolge DefaultValue → DefaultValueIfNullOrEmpty → DefaultValueMap.

Eine Verkettung im Sinne von „erst A, dann B auf das Ergebnis von A" gibt es bei SourceOperations damit nicht.

4 - Watermarks (watermark)

Die watermark-Tabelle speichert den letzten synchronisierten Stand pro Job — und verhindert so doppelte Übertragungen.

Die Tabelle watermark ist die Gedächtnisfunktion der DataBridge. Nach jedem Job-Lauf wird hier gespeichert, bis zu welchem Stand die Daten gelesen wurden. Beim nächsten Lauf startet der Quellabruf genau an diesem Punkt.

Diese Tabelle wird vom Deployment angelegt und zur Laufzeit automatisch befüllt — manuelle Einträge sind normalerweise nicht nötig. Es gibt jedoch Situationen, in denen ein gezielter Eingriff sinnvoll ist.


Tabellenstruktur

SpalteWertBeschreibung
PartitionKeywatermarkFest vorgegeben — immer watermark
RowKeyJobnameEntspricht dem RowKey des zugehörigen Jobs in der jobs-Tabelle
TimestampautomatischSystemseitig gesetzt, nicht bearbeitbar
WatermarkLetzter StandFormat abhängig vom WatermarkType des Jobs (siehe unten)
LastCronRunZeitstempelBeginn der letzten Ausführung des Jobs. Basis für die CRON-Intervallprüfung.

Watermark-Typen

Der Typ wird im Job über das Feld WatermarkType festgelegt und bestimmt, wie der gespeicherte Wert interpretiert wird.

datetime — Vollständiger Zeitstempel

Für Quellsysteme, die Änderungen über ein Datum-/Uhrzeit-Feld tracken. Typisch für Business Central (lastModifiedDateTime).

Format: yyyy-MM-ddTHH:mm:ss.fffZ

Beispielwert: 2026-05-31T08:15:00.000Z

Der Filter im Job sieht dann so aus:

{{lastModifiedDateTime gt %watermark%}}

date — Nur Datum

Für Quellsysteme, bei denen nur das Datum (ohne Uhrzeit) relevant ist. Typisch für NAV-Systeme mit datumbasiertem Tracking.

Format: yyyy-MM-dd

Beispielwert: 2026-05-31

string — Change Tracking Token

Für Dataverse / D365CE: Die Change Tracking API gibt bei jedem Abruf einen opaken Token zurück, der den aktuellen Änderungsstand repräsentiert. Dieser Token wird als string gespeichert und beim nächsten Lauf direkt an die API übergeben — kein Datumsvergleich, kein Risiko fehlender Änderungen.

Format: opake Zeichenkette (von Dataverse vergeben)

Beispielwert: 892290!08/10/2026 10:00:00

Schreibweise und unbekannte Typen

Der Typ wird ohne Beachtung von Groß-/Kleinschreibung und ohne umgebende Leerzeichen erkannt — datetime, DateTime und DATETIME sind gleichwertig.


Wann wird der Watermark aktualisiert?

Der Watermark wird am Ende der Erkennungsphase fortgeschrieben — also sobald alle gefundenen Änderungen in die Queue geschrieben sind, und bevor das Zielsystem beschrieben wurde. Für die Zustellung ins Ziel sorgen danach die Queue-Mechanismen (Wiederholung, Dead-Letter).

Im Einzelnen:

  1. Beim Lesen führt die DataBridge den Änderungsmarker (ChangeTracker) der verarbeiteten Datensätze mit
  2. Bei date und datetime wird jeweils der höhere der beiden Werte behalten, bei string gewinnt immer der zuletzt gelesene Token — ein opaker Token hat keine Ordnung
  3. Nach dem Leeren des letzten Batches wird der Endstand in die Tabelle geschrieben
  4. LastCronRun wird auf den Zeitpunkt gesetzt, zu dem der Job begonnen hat

Bricht ein Job mit einem Fehler ab, bleibt der Watermark auf dem zuletzt geschriebenen Stand. Beim nächsten Lauf wird ab diesem Punkt erneut gelesen.

Zeitzonen

Zeitstempel werden zeitzonenunabhängig verglichen. Bis v2.0 wurde die Zeitangabe in die lokale Zeit des Servers umgerechnet — beim Typ date konnte das über eine Tagesgrenze springen und das Vergleichsergebnis je nach Betriebsstandort verändern.


Erster Lauf — kein Eintrag vorhanden

Existiert für einen Job noch kein Watermark-Eintrag, legt die DataBridge ihn beim ersten Lauf automatisch an. Als Startpunkt wird ein möglichst früher Wert verwendet:

TypInitialwert
datetime0001-01-01T00:00:00.000Z
date0001-01-01
string(leer)

Das bedeutet: der erste Lauf lädt alle vorhandenen Datensätze aus dem Quellsystem. Bei großen Datenmengen sollte dies zu einem Zeitpunkt mit geringer Last geschehen.


Manueller Eingriff — Wann und warum

Vollständigen Neulauf erzwingen

Den Wert in der Watermark-Spalte leeren oder auf den Initialwert zurücksetzen. Beim nächsten Lauf werden alle Datensätze erneut übertragen.

Typische Anwendungsfälle:

  • Mapping wurde grundlegend geändert und alle Datensätze sollen neu gemappt werden
  • Zielsystem wurde zurückgesetzt oder neu aufgebaut
  • Datenverlust im Zielsystem

Partiellen Neulauf ab bestimmtem Datum

Den Watermark-Wert manuell auf ein Datum setzen, ab dem neu gelesen werden soll:

2026-01-01T00:00:00.000Z

Damit werden nur Datensätze übertragen, die seit diesem Datum geändert wurden.

Bei WatermarkType = string ist das nicht möglich — der Token stammt aus Dataverse und lässt sich nicht sinnvoll von Hand konstruieren. Dort bleibt nur das vollständige Leeren.

LastCronRun zurücksetzen

Wenn ein Job mit eigenem Schedule nicht zum erwarteten Zeitpunkt ausgeführt wurde, kann LastCronRun manuell auf einen früheren Wert gesetzt werden. Die DataBridge erkennt dann, dass das Intervall abgelaufen ist, und führt den Job beim nächsten Timer-Aufruf aus.