Anbietermanifestspezifikation

In diesem Abschnitt wird erläutert, wie ein Datenspeicheranbieter die Typen und Funktionen im Datenspeicher unterstützen kann.

Entitätsdienste werden unabhängig von einem bestimmten Datenspeicheranbieter ausgeführt. Datenanbieter können jedoch explizit definieren, wie Modelle, Zuordnungen und Abfragen mit einem zugrunde liegenden Datenspeicher interagieren. Ohne eine Abstraktionsebene zielen Entitätsdienste lediglich auf einen bestimmten Datenspeicher oder einen Datenanbieter ab.

Vom Anbieter unterstützte Typen werden direkt oder indirekt von der zugrunde liegende Datenbank unterstützt. Bei diesen Typen muss es sich nicht unbedingt um die genauen Speichertypen handeln, sondern um die Typen, die der Anbieter für die Unterstützung von Entity Framework verwendet. Anbieter-/Speichertypen werden mit den EDM (Entity Data Model)-Begriffen beschrieben.

Die Parameter und Rückgabetypen für die vom Datenspeicher unterstützten Funktionen werden in EDM-Begriffen angegeben.

Anforderungen

Entity Framework und der Datenspeicher müssen in der Lage sein, Daten in bekannten Typen ohne Datenverlust oder Abschneiden in beide Richtungen zu übergeben.

Das Anbietermanifest muss zur Entwurfszeit von Tools geladen werden können, ohne eine Verbindung mit dem Datenspeicher öffnen zu müssen.

Für Entity Framework muss die Groß-/Kleinschreibung beachtet werden, dies muss jedoch nicht für den zugrunde liegenden Datenspeicher gelten. Wenn EDM-Artefakte (z. B. Bezeichner und Typnamen) im Manifest definiert und verwendet werden, muss auf die Groß- und Kleinschreibung in Entity Framework geachtet werden. Wenn das Anbietermanifest Datenspeicherelemente enthält, bei denen die Groß-/Kleinschreibung beachtet werden muss, muss diese im Anbietermanifest beibehalten werden.

Entity Framework erfordert für alle Datenanbieter ein Anbietermanifest. Wenn Sie versuchen, einen Anbieter zu verwenden, der über kein Anbietermanifest mit Entity Framework verfügt, tritt ein Fehler auf.

In der folgenden Tabelle werden die Arten von Ausnahmen beschrieben, die Entity Framework auslöst, wenn durch Anbieterinteraktion Ausnahmen auftreten:

Problem Ausnahme

Der Anbieter unterstützt GetProviderManifest in DbProviderServices nicht.

ProviderIncompatibleException

Fehlendes Anbietermanifest: Beim Versuch, das Anbietermanifest abzurufen, gibt der Anbieter NULL zurück.

ProviderIncompatibleException

Ungültiges Anbietermanifest: Beim Versuch, das Anbietermanifest abzurufen, gibt der Anbieter ungültiges XML zurück.

ProviderIncompatibleException

Szenarien

Ein Anbieter sollte die folgenden Szenarien unterstützen:

Schreiben eines Anbieters mit symmetrischer Typzuordnung

Sie können einen Anbieter für Entity Framework schreiben, sodass unabhängig von der Zuordnungsrichtung jeder Speichertyp einem einzelnen EDM-Typ zugeordnet wird. Bei Anbietertypen mit einer sehr einfachen Zuordnung, die EDM-Typen entsprechen, können Sie eine symmetrische Lösung verwenden, da das Typsystem einfach ist oder den EDM-Typen entspricht.

Sie können die Einfachheit der Domäne nutzen und ein statisches deklaratives Anbietermanifest erstellen.

Sie schreiben eine XML-Datei mit zwei Abschnitten:

  • Eine Liste der hinsichtlich des "EDM-Äquivalents" eines Speichertyps oder einer Funktion ausgedrückten Anbietertypen. Speichertypen verfügen über äquivalente EDM-Typen. Speicherfunktionen verfügen über entsprechende EDM-Funktionen. So ist "varchar" z. B. ein SQL Server-Typ, der entsprechende EDM-Typ ist jedoch "string".

  • Eine Liste der vom Anbieter unterstützen Funktionen, wobei die Parameter und Rückgabetypen mit EDM-Begriffen ausgedrückt werden.

Schreiben eines Anbieters mit asymmetrischer Typzuordnung

Wenn Sie einen Datenspeicheranbieter für Entity Framework schreiben, unterscheidet sich die EDM-Anbieter-Typzuordnung für einige Typen möglicherweise von der Anbieter-EDM-Typzuordnung. So wird beispielsweise "unbounded EDM PrimitiveTypeKind.String" möglicherweise "nvarchar (4000)" für den Anbieter zugeordnet, während "nvarchar (4000)" dem Typ "EDM PrimitiveTypeKind.String(MaxLength=4000)" zugeordnet wird.

Sie schreiben eine XML-Datei mit zwei Abschnitten:

  • Eine Liste von Anbietertypen in EDM-Begriffen sowie eine Definition der Zuordnung in beide Richtungen: EDM-Anbieter und Anbieter-EDM.

  • Eine Liste der vom Anbieter unterstützen Funktionen, wobei die Parameter und Rückgabetypen mit EDM-Begriffen ausgedrückt werden.

Ermittelbarkeit des Anbietermanifests

Das Manifest wird indirekt von mehreren Komponententypen der Entitätsdienste (z. B. Tools oder Abfrage) verwendet. Die direktere Nutzung erfolgt jedoch für die Metadaten mithilfe des Metadaten-Ladeprogramms des Datenspeichers.

dfb3d02b-7a8c-4d51-ac5a-a73d8aa145e6

Anbieter können jedoch unterschiedliche Speicher oder unterschiedliche Versionen des gleichen Speichers unterstützen. Daher muss ein Anbieter für jeden unterstützten Datenspeicher ein anderes Manifest melden.

Anbietermanifesttoken

Beim Öffnen einer Datenspeicherverbindung kann der Anbieter Informationen abfragen, um das richtige Manifest zurückzugeben. Dies kann in Offlineszenarien unmöglich sein, in denen entweder die Verbindungsinformationen nicht zur Verfügung stehen oder keine Verbindung mit dem Datenspeicher hergestellt werden kann. Identifizieren Sie das Manifest mit dem ProviderManifestToken-Attribut des Schema-Elements in der SSDL-Datei. Es gibt kein erforderliches Format für dieses Attribut. Der Anbieter wählt die Mindestinformationen aus, die erforderlich sind, um ein Manifest zu identifizieren, ohne eine Verbindung mit dem Speicher zu öffnen.

Beispiel:

<Schema Namespace="Northwind" Provider="System.Data.SqlClient" ProviderManifestToken="2005" xmlns:edm="https://schemas.microsoft.com/ado/2006/04/edm/ssdl" xmlns="https://schemas.microsoft.com/ado/2006/04/edm/ssdl">

Programmiermodell für das Anbietermanifest

Anbieter werden von DbXmlEnabledProviderManifest abgeleitet, sodass die Manifeste deklarativ angegeben werden können. In der folgenden Abbildung wird die Klassenhierarchie eines Anbieters dargestellt:

Keine

Ermittelbarkeits-API

Das Anbietermanifest wird vom Speichermetadaten-Ladeprogramm (StoreItemCollection) entweder über eine Datenspeicherverbindung oder mit einem Anbietermanifesttoken geladen.

Verwenden einer Datenspeicherverbindung

Wenn die Datenspeicherverbindung verfügbar ist, rufen Sie DbProviderServices.GetProviderManifestToken auf, um das Token zurückzugeben, das an die GetProviderManifest-Methode übergeben wird, die DbProviderManifest zurückgibt. Diese Methode delegiert zur Implementierung von GetDbProviderManifestToken des Anbieters.

public string GetProviderManifestToken(DbConnection connection);
public DbProviderManifest GetProviderManifest(string manifestToken);

Verwenden eines Anbietermanifesttokens

Für das Offlineszenario wird das Token der SSDL-Darstellung ausgewählt. SSDL ermöglicht das Festlegen eines ProviderManifestToken (weitere Informationen finden Sie unter Schema-Element (SSDL)). Wenn beispielsweise eine Verbindung nicht geöffnet werden kann, verfügt SSDL über ein Anbietermanifesttoken, das Informationen über das Manifest angibt.

public DbProviderManifest GetProviderManifest(string manifestToken);

Anbietermanifestschema

Das Schema der für die einzelnen Anbieter definierten Informationen beinhaltet die statischen Informationen, die von Metadaten genutzt werden:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified"
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
   targetNamespace="https://schemas.microsoft.com/ado/2006/04/edm/providermanifest"
   xmlns:pm="https://schemas.microsoft.com/ado/2006/04/edm/providermanifest">

  <xs:element name="ProviderManifest">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Types" type="pm:TTypes" minOccurs="1" maxOccurs="1" />
        <xs:element name="Functions" type="pm:TFunctions" minOccurs="0" maxOccurs="1"/>
      </xs:sequence>
      <xs:attribute name="Namespace" type="xs:string" use="required"/>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="TVersion">
    <xs:attribute name="Major" type="xs:int" use="required" />
    <xs:attribute name="Minor" type="xs:int" use="required" />
    <xs:attribute name="Build" type="xs:int" use="required" />
    <xs:attribute name="Revision" type="xs:int" use="required" />
  </xs:complexType>

  <xs:complexType name="TIntegerFacetDescription">
    <xs:attribute name="Minimum" type="xs:int" use="optional" />
    <xs:attribute name="Maximum" type="xs:int" use="optional" />
    <xs:attribute name="DefaultValue" type="xs:int" use="optional" />
    <xs:attribute name="Constant" type="xs:boolean" default="false" />
  </xs:complexType>

  <xs:complexType name="TBooleanFacetDescription">
    <xs:attribute name="DefaultValue" type="xs:boolean" use="optional" />
    <xs:attribute name="Constant" type="xs:boolean" default="true" />
  </xs:complexType>

  <xs:complexType name="TDateTimeFacetDescription">
    <xs:attribute name="Constant" type="xs:boolean" default="false" />
  </xs:complexType>

  <xs:complexType name="TFacetDescriptions">
    <xs:choice maxOccurs="unbounded">
      <xs:element name="Precision" minOccurs="0" maxOccurs="1" type="pm:TIntegerFacetDescription"/>
      <xs:element name="Scale" minOccurs="0" maxOccurs="1" type="pm:TIntegerFacetDescription"/>
      <xs:element name="MaxLength" minOccurs="0" maxOccurs="1" type="pm:TIntegerFacetDescription"/>
      <xs:element name="Unicode" minOccurs="0" maxOccurs="1" type="pm:TBooleanFacetDescription"/>
      <xs:element name="FixedLength" minOccurs="0" maxOccurs="1" type="pm:TBooleanFacetDescription"/>
    </xs:choice>
  </xs:complexType>

  <xs:complexType name="TType">
    <xs:sequence>
      <xs:element name="FacetDescriptions" type="pm:TFacetDescriptions" minOccurs="0" maxOccurs="1"/>
    </xs:sequence>
    <xs:attribute name="Name" type="xs:string" use="required"/>
    <xs:attribute name="PrimitiveTypeKind" type="pm:TPrimitiveTypeKind" use="required" />
  </xs:complexType>

  <xs:complexType name="TTypes">
    <xs:sequence>
      <xs:element name="Type" type="pm:TType" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:attributeGroup name="TFacetAttribute">
    <xs:attribute name="Precision" type="xs:int" use="optional"/>
    <xs:attribute name="Scale" type="xs:int" use="optional"/>
    <xs:attribute name="MaxLength" type="xs:int" use="optional"/>
    <xs:attribute name="Unicode" type="xs:boolean" use="optional"/>
    <xs:attribute name="FixedLength" type="xs:boolean" use="optional"/>
  </xs:attributeGroup>

  <xs:complexType name="TFunctionParameter">
    <xs:attribute name="Name" type="xs:string" use="required" />
    <xs:attribute name="Type" type="xs:string" use="required" />
    <xs:attributeGroup ref="pm:TFacetAttribute" />
    <xs:attribute name="Mode" type="pm:TParameterDirection" use="required" />
  </xs:complexType>

  <xs:complexType name="TReturnType">
    <xs:attribute name="Type" type="xs:string" use="required" />
    <xs:attributeGroup ref="pm:TFacetAttribute" />
  </xs:complexType>

  <xs:complexType name="TFunction">
    <xs:choice minOccurs="0" maxOccurs ="unbounded">
      <xs:element name ="ReturnType" type="pm:TReturnType" minOccurs="0" maxOccurs="1" />
      <xs:element name="Parameter" type="pm:TFunctionParameter" minOccurs="0" maxOccurs="unbounded"/>
    </xs:choice>
    <xs:attribute name="Name" type="xs:string" use="required" />
    <xs:attribute name="Aggregate" type="xs:boolean" use="optional" />
    <xs:attribute name="BuiltIn" type="xs:boolean" use="optional" />
    <xs:attribute name="StoreFunctionName" type="xs:string" use="optional" />
    <xs:attribute name="NiladicFunction" type="xs:boolean" use="optional" />
    <xs:attribute name="ParameterTypeSemantics" type="pm:TParameterTypeSemantics" use="optional" default="AllowImplicitConversion" />
  </xs:complexType>

  <xs:complexType name="TFunctions">
    <xs:sequence>
      <xs:element name="Function" type="pm:TFunction" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:simpleType name="TPrimitiveTypeKind">
    <xs:restriction base="xs:string">
      <xs:enumeration value="Binary"/>
      <xs:enumeration value="Boolean"/>
      <xs:enumeration value="Byte"/>
      <xs:enumeration value="Decimal"/>
      <xs:enumeration value="DateTime"/>
      <xs:enumeration value="Time"/>
      <xs:enumeration value="DateTimeOffset"/>        
      <xs:enumeration value="Double"/>
      <xs:enumeration value="Guid"/>
      <xs:enumeration value="Single"/>
      <xs:enumeration value="SByte"/>
      <xs:enumeration value="Int16"/>
      <xs:enumeration value="Int32"/>
      <xs:enumeration value="Int64"/>
      <xs:enumeration value="String"/>
    </xs:restriction>
  </xs:simpleType>


  <xs:simpleType name="TParameterDirection">
    <xs:restriction base="xs:string">
      <xs:enumeration value="In"/>
      <xs:enumeration value="Out"/>
      <xs:enumeration value="InOut"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="TParameterTypeSemantics">
    <xs:restriction base="xs:string">
      <xs:enumeration value="ExactMatchOnly" />
      <xs:enumeration value="AllowImplicitPromotion" />
      <xs:enumeration value="AllowImplicitConversion" />
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

Typknoten

Der Typknoten des Anbietermanifests enthält Informationen über die Typen, die vom Datenspeicher oder Anbieter systemeigen unterstützt werden.

Typknoten

Jeder Typknoten definiert einen Anbietertyp mit EDM-Begriffen. Der Typknoten beschreibt den Namen des Anbietertyps, Informationen über den Modelltyp, dem er zugeordnet wird, und die Facets, mit denen die Typzuordnung beschrieben wird.

Um diese Typinformationen im Anbietermanifest auszudrücken, muss jede TypeInformation-Deklaration mehrere Facetbeschreibungen für die einzelnen Typen definieren:

Attributname Datentyp Erforderlich Standardwert Beschreibung

Name

Zeichenfolge

Ja

nicht verfügbar

Anbieterspezifischer Datentypname

PrimitiveTypeKind

PrimitiveTypeKind

Ja

nicht verfügbar

EDM-Typenname

Funktionsknoten

Jede Funktion definiert eine einzelne, über den Anbieter verfügbare Funktion.

Attributname Datentyp Erforderlich Standardwert Beschreibung

Name

Zeichenfolge

Ja

nicht verfügbar

Bezeichner/Name der Funktion

ReturnType

Zeichenfolge

Nein

Void

Der EDM-Rückgabetyp der Funktion

Aggregate

Boolean

Nein

False

"True", wenn es sich bei der Funktion um eine Aggregatfunktion handelt.

BuiltIn

Boolean

Nein

True

"True", wenn die Funktion in den Datenspeicher integriert ist.

StoreFunctionName

Zeichenfolge

Nein

<Name>

Funktionsname im Datenspeicher. Ermöglicht eine Umleitungsebene für Funktionsnamen.

NiladicFunction

Boolean

Nein

False

"True", wenn die Funktion keine Parameter erfordert und ohne Parameter aufgerufen wird.

ParameterType

Semantik

ParameterSemantics

Nein

AllowImplicit

Konvertierung

Hiermit kann ausgewählt werden, wie die Abfragepipeline mit Parametertypersetzung umgehen soll:

  • ExactMatchOnly

  • AllowImplicitPromotion

  • AllowImplicitConversion

Parameterknoten

Jede Funktion verfügt über eine Auflistung von einem oder mehreren Parameterknoten.

Attributname Datentyp Erforderlich Standardwert Beschreibung

Name

Zeichenfolge

Ja

nicht verfügbar

Bezeichner/Name des Parameters.

Typ

Zeichenfolge

Ja

nicht verfügbar

Der EDM-Typ des Parameters.

Modus

Parameter

Richtung

Ja

nicht verfügbar

Richtung des Parameters:

  • in

  • out

  • inout

Namespace-Attribut

Jeder Datenspeicheranbieter muss einen Namespace oder eine Gruppe von Namespaces für die im Manifest definierten Informationen definieren. Dieser Namespace kann in Entity SQL-Abfragen verwendet werden, um Namen von Funktionen und Typen aufzulösen. Zum Beispiel: SqlServer. Dieser Namespace muss sich vom kanonischen Namespace "EDM" unterscheiden, der von den Entitätsdiensten für Standardfunktionen definiert wird, die von Entity SQL-Abfragen unterstützt werden sollen.

Siehe auch

Konzepte

Schreiben eines Entity Framework-Datenanbieters