Farbschema: Riviera
Sie befinden sich hier: start » de » Dokumentation » Datenintegration und Datenzugriff » WKL OData-ODBC-Treiber » Referenz des OData-ODBC-Treibers » Anforderungen an einen OData-Dienst (Referenz)

Anforderungen an einen OData-Dienst (Referenz)

Der Treiber spricht jeden OData-v4-Dienst, der die Pflichtmerkmale unten anbietet. Bietet ein Dienst zusätzlich eine der Erweiterungen an, nutzt der Treiber sie; ohne sie verhält er sich, als gäbe es sie nicht. Diese Seite brauchen Sie, wenn Sie prüfen, ob ein Dienst mit dem Treiber zusammenarbeitet, oder wenn Sie selbst einen Dienst für Access-Anwendungen bauen. Der Datendienst Wkl.Data.Gateway bietet alle Merkmale dieser Seite an.

Syntax

GET  <Dienststamm>/$metadata                       Schemadokument (CSDL, XML)
GET  <Dienststamm>/<Menge>?$select=…&$filter=…     Lesen, Antwort JSON
POST/PATCH/DELETE <Dienststamm>/<Menge>[(<Schlüssel>)]   Schreiben

Parameter

Die Merkmale sind nach ihrer Verbindlichkeit für den Treiber gegliedert: Ohne die Pflicht zum Lesen verbindet der Treiber nicht oder liest falsch; ohne die Pflicht zum Schreiben bleiben alle Mengen schreibgeschützt; die Erweiterungen sind Empfehlungen, deren Fehlen eine Funktion abschaltet, aber nichts verfälscht. Die Grundlagen von OData v4 beschreiben die Normen von OASIS: OData Version 4.01 Part 1: Protocol, Part 2: URL Conventions (Abfrageoptionen, Literale), OData Common Schema Definition Language (CSDL) XML Representation 4.01 ($metadata) und OData JSON Format 4.01. Der Treiber verlangt nur Merkmale, die schon OData 4.0 kennt; $query (4.01) nutzt er, wenn vorhanden.

Pflicht zum Lesen

MerkmalWofür der Treiber es braucht
$metadata (CSDL) mit Entitätsmengen, Eigenschaften, Typen, Facetten und SchlüsselnKatalogfunktionen, Typabbildung (siehe Escape-Klauseln und Datentypen)
Nur die für den Aufrufer freigegebenen Entitätsmengen in $metadataAccess bietet an, was der Benutzer auch lesen darf. Das ist eine Anforderung an die Sicherheit des Dienstes, nicht an die Technik: Der Treiber verbindet auch ohne sie, zeigt dann aber Tabellen an, deren Lesen scheitert
$select, $filter, $orderby, $top, $skipÜbersetzung von SELECT
In $filter die Literale von OData v4 ohne Typnamen, auch für Edm.Guid (Id eq 3333…), und Vergleiche zweier Eigenschaften (ParentId eq Id)Bedingungen auf uniqueidentifier-Spalten; Wurzeln eines Baums. Ein Dienst ohne Feld-gegen-Feld antwortet 400, der Treiber meldet 42000 – nur diese eine Bedingung scheitert
$countCOUNT(*) ohne Laden der Zeilen
@odata.nextLinkgroße Mengen seitenweise lesen
Prefer: odata.maxpagesize (empfohlen)größere Seiten, wenn nur schmale Spalten gelesen werden, etwa die Schlüssel. Ein Dienst, der den Wunsch nicht beachtet, liefert seine eigene Seitengröße; der Treiber liest dann mehr Seiten, sonst ändert sich nichts
Antworten als JSONder Treiber liest kein Atom/XML

Pflicht zum Schreiben

MerkmalWofür der Treiber es braucht
Schlüssel im Entitätstyp und Adressierung Menge(Schlüssel)PATCH, DELETE (gelesen wird über $filter, nie über die Schlüsseladresse); eine Menge ohne Schlüssel ist schreibgeschützt (außer mit den Aktionen für Tabellen ohne Schlüssel, unten)
POST, PATCH, DELETE mit JSON-Rumpf; Antwort mit dem gespeicherten SatzAnlegen, Ändern, Löschen
If-Match, Antwort 412 bei veralteter Version, Ankündigung mit Core.OptimisticConcurrencySchreibkonflikte erkennen; ohne diese Ankündigung weist der Treiber Ändern und Löschen ab (Anlegen bleibt möglich). Der Treiber bildet das ETag selbst aus der angekündigten Spalte (Binärwert als W/"<Base64>"); der Dienst muss diese Form annehmen, siehe Was der Treiber beim Schreiben voraussetzt

Erweiterungen (empfohlen), die der Treiber nutzt, wenn der Dienst sie anbietet

MerkmalWoran der Treiber es erkenntWofür
Adresse für eigene Anweisungen: nimmt {"sql": …, "parameters": {…}} an, antwortet {"columns": […], "data": […], "affectedRowCount": …}die Verbindung nennt sie (PASSTHROUGH), oder $metadata nennt sie in Store.PassThroughnicht übersetzbare Anweisungen, Pass-Through-Abfragen
Org.OData.Aggregation.V1.ApplySupported mit den Transformationen filter, compute, groupby, aggregate; Aggregation.CustomAggregationMethods mit Wkl.Store.V1.countAnkündigung in $metadataSummen, Gruppen, HAVING, DISTINCT ohne eigene Anweisungen; COUNT(Spalte)
Gebundene Aktionen UpdateByOriginal und DeleteByOriginal an einer Menge ohne Schlüssel$metadata deklariert beide für den Typ der MengeÄndern und Löschen über die alten Werte
POST <Ressource>/$query mit den Abfrageoptionen im Rumpf (OData 4.01)ausprobiert, sobald eine Adresse länger als MAXURLLENGTH wäre; ohne diese Form antwortet der Dienst 404, 405 oder 501, und die Anfrage geht doch als GETlange Bedingungen
Anmeldung über HTTP Negotiatedie Verbindung schaltet sie ein (AUTH=WINDOWS); der Dienst verlangt sie mit 401 und WWW-Authenticate: NegotiateWindows-Anmeldung ohne Geheimnis
Anmeldung über HTTP Basicdie Verbindung nennt UID und PWDAnmeldung mit Name und Kennwort
Schlüssel in einer KopfzeileAPIKEY/APIKEYENV oder AUTH=KEY; Kopfzeile APIKEYHEADER, Vorgabe X-Api-KeyDienstschlüssel und persönliche Schlüssel
Zweiter Faktor: 401 mit WWW-Authenticate: Wkl-Totp … endpoint="<Pfad>"; POST <Pfad> mit {"code": "…"} liefert 201 mit einer SitzungHerausforderung in der AntwortCodeabfrage, Sitzung in der Kopfzeile X-Wkl-Session
Identitätswahl: Kopfzeile X-Wkl-Role; Ablehnung 403 mit X-Wkl-Roles (prozentkodiertes UTF-8, durch Kommas getrennt)Kopfzeile in der AntwortAuswahl der Datenbank-Identität
Idempotency-Key an POST, PATCH, DELETE: eine Wiederholung erhält die gespeicherte erste Antwort– (der Treiber schickt den Schlüssel immer)Wiederholung nach Verbindungsabbruch ohne doppelten Satz
Vokabular Wkl.Store.V1 (Begriffe unten)Annotationen in $metadataAuftreten als Datenbankprodukt, Schema als TABLE_SCHEM, Typnamen, Indizes, Statistik für die Planung von Access
Transaktionen: Store.Transactions am Entitätscontainer nennt eine Adresse; POST dorthin liefert 201 mit {"id": "…"}; Anfragen mit der Kopfzeile Wkl-Transaction: <id> laufen in ihr; POST <Adresse>/<id>/commit bzw. /rollback schließt sie (204); eine unbekannte oder beendete Kennung 404, eine vom Dienst zurückgenommene 409Annotation in $metadataBeginTrans/CommitTrans/Rollback, BeginTransaction; SQL_TXN_CAPABLE = SQL_TC_ALL
Meldungen der Datenbank in error.details einer Ablehnung: je Eintrag code = Meldungsnummer als Text, message, dazu sqlState (fünf Zeichen)Einträge mit Zahl als codeein Diagnosesatz je Meldung mit der Nummer als native Fehlernummer und dem genannten SQLSTATE (fehlt er: 42000), wie beim Treiber von SQL Server; ohne solche Einträge ein Satz mit dem HTTP-Status als Nummer
Core.ComputedAnnotation an der Eigenschaftnicht schreibbare Spalten (Identität, berechnet, Zeilenversion); der Treiber meldet sie über SQLColAttribute (SQL_DESC_UPDATABLE) als schreibgeschützt, alle übrigen als „unbekannt“

Begriffe des Vokabulars Wkl.Store.V1. Das Vokabular ist eine Erweiterung dieses Produkts, kein Teil von OData. Ein Dienst, der es anbietet, legt es unter einer eigenen Adresse ab und bindet es mit edmx:Reference ein (Beispiel unten); der Treiber erkennt die Begriffe am Namensraum, mit oder ohne Alias.

BegriffTypGilt fürBedeutung für den Treiber
ProductEdm.StringEntitätscontainerName des Datenbankprodukts, gemeldet über SQLGetInfo(SQL_DBMS_NAME); ohne den Begriff meldet der Treiber OData und Version 4.0
ProductVersionEdm.StringEntitätscontainerHaupt- und Nebenversion (17.00), gemeldet als SQL_DBMS_VER in der Form 17.00.0000
SchemaEdm.StringEntitätscontainerSchema des Dienststamms, gemeldet als TABLE_SCHEM; ohne es speichert Access bei einer als dbo.Tabelle verknüpften Tabelle einen leeren Quellnamen
PassThroughEdm.StringEntitätscontainerAdresse für eigene Anweisungen; nur am selben Ursprung wie der Dienststamm übernommen
TransactionsEdm.StringEntitätscontainerAdresse, die eine Transaktion öffnet
TypeEdm.StringEigenschaftTypname der Datenbank, bei einer selbst nummerierten Spalte mit identity
IndexesListe von Index (Name, Unique, Primary, Clustered, Columns)EntitätstypIndizes für SQLStatistics
Rows, PagesEdm.Int64EntitätstypZeilen und Datenseiten für SQLStatistics (CARDINALITY, PAGES); Schätzwerte

Zusagen je Art des Dienstes

Welche Zusage des Treibers gilt, hängt davon ab, was der Dienst anbietet und einhält. Der Treiber erkennt Ankündigungen in $metadata, nicht aber, ob ein Dienst eine Kopfzeile wie Idempotency-Key tatsächlich beachtet. Was er nicht erkennen kann, müssen Sie vor dem Einsatz beim Anbieter des Dienstes klären oder selbst prüfen.

Zusagebeliebiger OData-v4-Dienst mit den PflichtmerkmalenDienst mit den Erweiterungen dieser SeiteDatendienst Wkl.Data.Gateway
Lesen, Filtern, Sortieren, Zählen auf dem Dienstjajaja
Schreiben mit Schreibkonfliktja, mit Core.OptimisticConcurrencyjaja
Wiederholung eines Lesens nach Verbindungsabbruchjajaja
Wiederholung einer Änderung ohne doppelten Satznein: der Treiber wiederholt in der Vorgabe trotzdem; ein Dienst, der Idempotency-Key übergeht, kann einen Satz doppelt anlegen. Abhilfe: RETRY=OFFnur, wenn der Dienst die Kopfzeile einhält – nicht erkennbar, beim Anbieter klärenja: der Dienst merkt sich die Antwort zehn Minuten im Arbeitsspeicher
Transaktionennein (HYC00; DAO ohne Wirkung)mit Store.Transactionsja
Summen und Gruppen ohne Durchreicheneinmit Aggregation.ApplySupportedja
Nicht übersetzbare Anweisungennein, 42000mit Durchreicheadresseja: geprüfte Anweisungen für jeden Aufrufer, dessen Regel den Alias nennt; ungeprüftes SQL nur mit Freigabe
Zweiter Faktor, Identitätswahlneinmit den Herausforderungen dieser Seiteja

Was ein Dienst für die Wiederholung zusagen muss. Der Treiber wiederholt eine Änderung höchstens zweimal, nach 1 und nach 3 Sekunden, mit demselben Idempotency-Key. Der Dienst muss deshalb die erste Antwort zu einem Schlüssel mindestens einige Sekunden aufbewahren und auf die Wiederholung genau diese Antwort geben, ohne die Änderung noch einmal auszuführen. Eine überschrittene Zeitgrenze (HYT00) wiederholt der Treiber nicht: Ob die Änderung ausgeführt wurde, ist dann unbekannt, und die Anwendung muss den Satz neu lesen. Den Abschluss einer Transaktion (commit, rollback) wiederholt er ebenfalls nicht.

Was ein Dienst aus Sicherheitsgründen zusagen muss. Er lehnt eine Anfrage ohne gültige Anmeldung oder zweiten Faktor ab, bevor er etwas ausführt; der Treiber sendet sie danach erneut. Und er leitet Adressen unter dem Dienststamm nicht auf einen anderen Ursprung um (siehe Restrisiken).

Rückgabewert

Keiner. Der Treiber prüft die Merkmale beim Verbinden und beim jeweiligen Gebrauch, nicht vorab.

Bemerkungen

  • Ohne Core.OptimisticConcurrency stellt Access beim Ändern die alten Werte aller Spalten in die Bedingung. Das lässt sich in OData nicht ausdrücken; der Treiber weist es ab, statt die Prüfung fallen zu lassen. Abhilfe schafft der Dienst, etwa mit einer berechneten Nebenläufigkeitseigenschaft.
  • Ohne Gruppieren und ohne Adresse für eigene Anweisungen scheitern Summenabfragen und Verbünde aus Access mit „ODBC-Aufruf fehlgeschlagen“; siehe Fehlerbehebung.
  • Ohne Idempotency-Key-Unterstützung kann eine Wiederholung nach einem Verbindungsabbruch einen Satz doppelt anlegen oder einen Schreibkonflikt melden, obwohl die Änderung durchging. Ein Dienst, der die Kopfzeile nicht kennt, übergeht sie; der Treiber erkennt das nicht. Die Kopfzeile beschreibt ein abgelaufener Entwurf der IETF, kein Standard (siehe Normen und Spezifikationen).
  • Eigene Anweisungen auf der Leitung. Der Treiber schickt {"sql": …, "parameters": {…}} und erwartet {"columns": […], "data": […], "affectedRowCount": …}. Gebundene Werte bleiben Werte: Die Platzhalter ?, die ODBC nach Position zählt, werden zu benannten Platzhaltern – ein Fragezeichen in einer Zeichenkette, einem geklammerten Namen oder einem Kommentar bleibt dabei unangetastet. Eine Antwort ohne columns wird abgewiesen. Die Typen aus den Werten der ersten Zeile zu erschließen, hieße: eine ganze Zahl in einer Dezimalspalte wird zur Ganzzahl, ein Zeitpunkt wird Text, und ein leeres Ergebnis hat gar keine Form – während die Anwendung ihre Puffer bindet, bevor sie die erste Zeile liest.
  • Ausgabeparameter, weitere Ergebnismengen, Beschreiben. Bindet eine Anwendung Ausgabeparameter, schickt der Treiber zusätzlich "outputs": {"p1": "Edm.Int32", "p2": {"type": "Edm.String", "maxLength": 20}} und liest die Werte aus outputs der Antwort; weitere Ergebnismengen liest er aus results (je Menge columns, data, truncated). Fragt eine Anwendung vor dem Ausführen nach den Spalten, schickt er "describe": true und erwartet die Spalten der ersten Menge, ohne dass der Dienst etwas ausführt. Das Beschreiben verlangt er nur von einem Dienst, der die Adresse selbst in Store.PassThrough nennt: Ein Dienst, der describe übergeht, würde die Anweisung sonst ausführen. Liefert ein Dienst kein outputs, erhält die Anwendung NULL als Ausgabewert.
  • Beschreibung der Spalten. Neben name, type und den Facetten (maxLength, precision, scale) liest der Treiber drei optionale Angaben je Spalte: storeType (der Typname der Datenbank, wie Store.Type in $metadata), identity (true für einen Wert, den die Datenbank vergibt) und label (der Name, den die Datenbank der Spalte gibt, wo er von name abweicht). Zeilen sind JSON-Objekte; für eine Spalte ohne Namen oder mit einem schon vergebenen Namen muss der Dienst deshalb einen eigenen Schlüssel vergeben. Mit label zeigt der Treiber der Anwendung den Namen der Datenbank – leer oder doppelt, wie der ODBC Driver 18 – und liest die Werte unter name. Ohne label sieht die Anwendung diesen Schlüssel.
  • Store.PassThrough gilt nur am selben Ursprung (Schema, Rechner, Port) wie der Dienststamm.
  • Felder einer Antwort, die der Treiber nicht kennt, übergeht er. Auf dem Durchreichepfad liest er columns, data, affectedRowCount, truncated, results und outputs (siehe Grenzen).
  • Keine Umleitung an einen anderen Ursprung. Der Treiber folgt einer Umleitung nur beim Lesen und nur am selben Schema, Rechner und Port; leitet der Dienst anderswohin um, scheitert die Anfrage mit 08S01.

Beispiel

Ausschnitt eines Schemadokuments mit den Erweiterungen, die Access zum Bearbeiten und Gruppieren braucht:

<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Aggregation.V1.xml">
  <edmx:Include Namespace="Org.OData.Aggregation.V1" Alias="Aggregation" />
</edmx:Reference>
<edmx:Reference Uri="https://daten.example.com/odata/v4/$vocabulary/Wkl.Store.V1.xml">
  <edmx:Include Namespace="Wkl.Store.V1" Alias="Store" />
</edmx:Reference>
…
<EntityContainer Name="Container">
  <Annotation Term="Store.Product" String="Microsoft SQL Server" />
  <Annotation Term="Store.ProductVersion" String="17.00" />
  <Annotation Term="Store.Schema" String="dbo" />
  <Annotation Term="Aggregation.ApplySupported">
    <Record>
      <PropertyValue Property="Transformations">
        <Collection><String>filter</String><String>compute</String><String>groupby</String><String>aggregate</String></Collection>
      </PropertyValue>
      <PropertyValue Property="Rollup" EnumMember="Aggregation.RollupType/None" />
    </Record>
  </Annotation>
  <Annotation Term="Aggregation.CustomAggregationMethods">
    <Collection><String>Wkl.Store.V1.count</String></Collection>
  </Annotation>
</EntityContainer>

So liefert es der Datendienst (gekürzt). Die Begriffe stehen mit dem Alias, den die edmx:Reference vergibt; der Treiber liest beide Schreibweisen.

Gilt für

Treiber Wkl OData, beide Bitbreiten. OData v2 und v3 sowie Dienste ohne $metadata oder ohne JSON werden nicht unterstützt.

Ausnahmen

SQLSTATEBedingung
42000Eine Anweisung lässt sich nicht übersetzen, und es gibt keine Adresse für eigene Anweisungen
HYC00Die Anwendung verlangt eine Transaktion, und der Dienst bietet keine an (kein Store.Transactions)
40001SQLEndTran mit Commit: Der Dienst hat die Transaktion schon zurückgenommen (nach einem Fehler, der sie unbrauchbar machte, oder nach seiner Leerlaufzeit); nichts davon ist gespeichert
08S01Der Dienst ist nicht erreichbar, oder ein Dokument bricht ab (etwa eine gestreamte Antwort)

Siehe auch

de/wiki/data-conectivity/odata-odbc/reference/requirements-for-the-service.txt · Zuletzt geändert: von Wolfgang van der Stille