Learn how to read OData metadata documents
- What the metadata document looks like
- What it describes
- How to navigate it
A key resource in any OData service is its metadata document. In this tutorial you’ll take a tour of a simple metadata document (the one for the Northbreeze service introduced in the previous tutorial in this mission).
Throughout this tutorial you should endeavor to use your own instance of the Northbreeze service (see the previous Northbreeze tutorial); for illustration purposes, URLs for the publicly available instance will be used here.
This tutorial belongs to the OData Deep Dive mission, a re-write of the original. The re-write is a work in progess, please proceed with caution! More info can be found in the blog post OData Deep Dive rewrite in the open.
- Step 1
Head over to your Northbreeze service and request the metadata document resource. The URL is formed from the OData service root:
https://odd.cfapps.eu10.hana.ondemand.com/northbreeze
with
$metadataadded as a further path segment:https://odd.cfapps.eu10.hana.ondemand.com/northbreeze/$metadata
Alongside the metadata document, there is another "fixed" resource, available from the service root directly. What is that resource?
- Step 2
Initially the content of this resource can be a little overwhelming. Here’s what the first part looks like:

But if we stare at it for long enough, it becomes less overwhelming and we start to see the structure.
What do you think the Version="4.0" refers to in the root element shown here?
- Step 3
Regard this drastically reduced version of the entire metadata document XML structure:
xmlCopy<?xml version="1.0" encoding="utf-8"?> <edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"> <edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Capabilities.V1.xml"></edmx:Reference> <edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/Common.xml"></edmx:Reference> <edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml"></edmx:Reference> <edmx:DataServices> <Schema Namespace="Main" xmlns="http://docs.oasis-open.org/odata/ns/edm"> <Annotation Term="Core.Links"></Annotation> <EntityContainer Name="EntityContainer"> <EntitySet Name="Products" EntityType="Main.Products"></EntitySet> <EntitySet Name="Categories" EntityType="Main.Categories"></EntitySet> <EntitySet Name="Suppliers" EntityType="Main.Suppliers"></EntitySet> </EntityContainer> <EntityType Name="Products"></EntityType> <EntityType Name="Categories"></EntityType> <EntityType Name="Suppliers"></EntityType> <Annotations Target="Main.EntityContainer/Categories"> <Annotation Term="Capabilities.DeleteRestrictions"></Annotation> </Annotations> </Schema> </edmx:DataServices> </edmx:Edmx>It allows us to see the overall structure of this resource, and start to feel a bit more comfortable navigating it. Being XML, the first thing we see is the XML declaration (
<?xml ...?>- see the Key terminology section of the XML page on Wikipedia), and then we have the document itself.The outermost (or “root”) element is
Edmx, which has:- a
Versionattribute which reflects the OData version - a namespace prefix
- a namespace declaration
It also contains, as children:
- a number of references to vocabularies
- a single
DataServiceselement
The primary area of interest to us in any metadata document is the content within the
DataServiceselement, as that’s where the rubber meets the road with respect to what the OData service represents for us as architects or developers. But it helps if we are comfortable with the rest of the document, the “context” for the content of theDataServiceselement so to speak, if only to be able to mentally put it aside, move past it and get to what we’re looking for.So we will look briefly at namespaces in the next step. We’ll look at OData vocabularies & annotations in the next couple of tutorials.
Is the XML declaration mandatory?
- a
- Step 4
While not critical to getting to the heart of what the metadata document conveys, its worth dwelling for a moment on all those element name prefixes (such as the
edmxpart of<edmx:Edmx>,<edmx:Reference>and so on).These are artifacts relating to the use of XML namespaces.
There are actually two different types of namespaces at play in these OData metadata document resources. There are the XML namespaces, which are the subject of this step. There are also OData namespaces. These are found in
Namespaceattributes of the<edmx:Include>and<Schema>elements. We’ll look at the schema namespace in a later step in this tutorial, and at the namespaces in the<edmx:Include>elements in the next tutorial.For the usual reasons, namespaces are used in XML to compartmentalize element and attribute names, which allow the use of various XML vocabularies (not to be confused with the OData vocabularies which we’ll look at next) together in a single document, without element and attribute name collisions.
These XML namespaces are declared with
xmlnsattributes, which are either in the purexmlnsform, or in axmlns:prefixform. The first form is how a default namespace is declared, the second is how non-default (named) namespaces are declared. Any element can be specified with a namespace prefix (such asedmx:Reference) or without (such as<Schema>). Elements without a specific namespace prefix are considered to belong to the default namespace.So, if we look again at the entire XML structure, differently compacted this time:
xmlCopy<?xml version="1.0" encoding="utf-8"?> <edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"> <edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Capabilities.V1.xml"> <edmx:Include Alias="Capabilities" Namespace="Org.OData.Capabilities.V1"/> </edmx:Reference> <edmx:DataServices> <Schema Namespace="Main" xmlns="http://docs.oasis-open.org/odata/ns/edm"> <Annotation Term="Core.Links"> ... </Annotation> <EntityContainer Name="EntityContainer"> <EntitySet Name="Products" EntityType="Main.Products"> ... </EntitySet> </EntityContainer> <EntityType Name="Products"> ... </EntityType> </Schema> </edmx:DataServices> </edmx:Edmx>we see that there are two XML namespaces at play, a named one (i.e. using a prefix) and a default one:
Namespace Prefix Covers http://docs.oasis-open.org/odata/ns/edmxedmxEdmx,Reference,Include,DataServiceshttp://docs.oasis-open.org/odata/ns/edm(default) Schema,EntityContainer,EntitySet,EntityTypeetcAs the primary area of interest in such resources is what’s in the
DataServicessection (the entity type definitions, the entitysets, annotations and so on) it makes sense to specify the namespace that encompasses the elements that are used for such definitions … as the the default, affording clarity in such declarations (i.e. less “busy”, as the element names aren’t prefixed).Within each EntityType definition in the metadata document, the key property in each case is identified using a PropertyRef element. In which namespace is this element?
- Step 5
To understand the context of the
DataServiceselement, let’s use what we learned in the Standards tutorial in this mission on navigating OData standards documents.We should refer to the OData standards document “OData Version 4.0. Part 3: Common Schema Definition Language (CSDL)”, the latest version being available at the canonical URL https://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part3-csdl.html, which brings us specifically to the “Oasis Standard Plus Errata 03” version which has its own URL https://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part3-csdl/odata-v4.0-errata03-os-part3-csdl-complete.html.
The document’s “Abstract” section tells us that we’re on the right track:
“OData services are described by an Entity Data Model (EDM). The Common Schema Definition Language (CSDL) defines an XML representation of the entity data model exposed by an OData service.”
In this document, section 3 Entity Model Wrapper tells us all about this context:
- the root
edmx:Edmxelement (a) is mandatory and (b) must contain a singleedmx:DataServiceselement - that single
edmx:DataServiceselement must contain one or moreedm:Schemaelements - it is in these
edm:Schemaelements that our OData service schemas (service and entity detail) are defined
In our case, there’s one schema, and therefore a single
edm:Schemaelement.The referenced OData standards document on CSDL is Part 3 of a Work Product that contains various components, Parts 1 and 2 being what, respectively?
- the root
- Step 6
The
edmprefix to theSchemaelement name here is from the documentation; in our particular metadata document the namespace represented by this prefix,http://docs.oasis-open.org/odata/ns/edm, is defined as the default (see the previous step). From now on, element names in the standards document that are prefixed withedmwill be written here without the prefix, to stay close to our specific metadata document.To become acquainted with the
Schemaelement, we can now jump to section 5 Schema to know what to expect inside it. The section tells us to expect one or more of the following elements:ActionAnnotationsAnnotationComplexTypeEntityContainerEntityTypeEnumTypeFunctionTermTypeDefinition
If we inspect what’s in our
Schema, we see these elements at the next level:Annotation(andAnnotations)EntityContainerEntityType
Visualizing our path through this metadata document, we’ve now found our way to what we really want to know:
textCopy+------+ | Edmx |--+ +------+ | | +--------------+ | DataServices |--+ +--------------+ | | +--------+ | Schema | +--------+ | +---------+-------+------------------+ | | | +-----------------+ +------------+ +------------+ | EntityContainer | | EntityType |-+ | Annotation |-+ +-----------------+ +------------+ | +------------+ | +------------+ +------------+Note that there is only a single entity container (see section 13 Entity Container), but multiple entity types and annotations.
Annotations are covered in a subsequent tutorial, so that leaves the
EntityContainerandEntityTypeelements. Let’s take these one at a time to round out our brief look at the metadata document.According to the "Entity Container" section (13) in the referenced OData standards document, which of these are defined in the EntityContainer element?
- Step 7
Before we do, we should make a note of one more thing at this level, and that’s the
Namespaceattribute in the<Schema>element:xmlCopy<Schema Namespace="Main" xmlns="http://docs.oasis-open.org/odata/ns/edm"> ... </Schema>Both attributes of this element relate to namespaces:
xmlnsgives us the XML namespace (as discussed previously)Namespaceis an OData mechanism
That OData namespace mechanism is described in the aforementioned CSDL standards document, in section 5.1.1 Attribute namespace, thus:
“A schema is identified by a namespace. All
edm:Schemaelements MUST have a namespace defined through aNamespaceattribute which MUST be unique within the document, and SHOULD be globally unique … It is combined with the name of elements in the entity model to create unique qualified names …”The value of this
Namespaceattribute isMain(this OData service is served from a CAP server, which generates the value from the service name).This is certainly unique within the metadata document itself, but the value is certainly not globally unique.
This is fine according to the “MUST” and “SHOULD” terms, which are defined according to RFC2119 (see section 1.1 Terminology):
- “MUST” means that the definition is an absolute requirement (which is fulfilled, here)
- “SHOULD” means that the definition is a recommendation
Incidentally, here are some values for this OData namespace definition from similar services curated and maintained by OASIS:
xml <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="NorthwindModel">xml <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Microsoft.OData.SampleService.Models.TripPin">Let’s have a brief look at where this
MainOData namespace is used. Here’s another drastically reduced version of the entire XML document, showing whereMainis found:xmlCopy<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"> <edmx:DataServices> <Schema Namespace="Main" xmlns="http://docs.oasis-open.org/odata/ns/edm"> <EntityContainer Name="EntityContainer"> <EntitySet Name="Products" EntityType="Main.Products"> ... </EntitySet> <EntitySet Name="Categories" EntityType="Main.Categories"> ... </EntitySet> <EntitySet Name="Suppliers" EntityType="Main.Suppliers"> ... </EntitySet> </EntityContainer> <EntityType Name="Products"> ... <NavigationProperty Name="Category" Type="Main.Categories" Partner="Products"> ... </NavigationProperty> <NavigationProperty Name="Supplier" Type="Main.Suppliers" Partner="Products"> ... </NavigationProperty> </EntityType> <EntityType Name="Categories"> ... <NavigationProperty Name="Products" Type="Collection(Main.Products)" Partner="Category"/> </EntityType> ... <Annotations Target="Main.EntityContainer/Categories"> <Annotation Term="Capabilities.DeleteRestrictions"> ... </Annotation> ... </Annotations> </Schema> </edmx:DataServices> </edmx:Edmx>The
Mainnamespace is used to prefix the “variable building blocks” of the schema when referencing them. So:- the
EntitySet“Products” refers toMain.Productsas the type of the entity contained - within the corresponding
EntityTypedefinition we see that theNavigationProperty“Category” is of typeMain.Categories
Following that to the “Categories”
EntityTypewe see that:- there’s another
NavigationProperty“Products” that leads back to theMain.Productstype, this time in aCollection( ... )expression (denoting a zero-or-more relationship)
Finally:
- annotations have targets, which are expressed as containees (such as the “Products”
EntitySet) of theMain.EntityContainerelement
According to the "Attribute namespace" section (5.1.1) in the referenced OData standards document, what is the term for the unique combination of the schema's namespace ("Main", in this case) with an element's name in the entity model?
- Step 8
The
EntityContainerelement within theSchemarepresents the “shop front” of the OData service. It’s here that the entitysets are declared. If there are any actions or functions defined in the service, they would be found listed here too, via<ActionImport>and<FunctionImport>elements respectively.If there are any relationships emanating from the
EntityTypeupon which anEntitySetis based, these are declared in that definition. For example, the “Products”EntityTypehas relationships with “Categories” and “Suppliers”, as declared with theNavigationPropertyBindingelements within the “Products”EntitySet:xmlCopy<EntitySet Name="Products" EntityType="Main.Products"> <NavigationPropertyBinding Path="Category" Target="Categories"/> <NavigationPropertyBinding Path="Supplier" Target="Suppliers"/> </EntitySet>Thus the
EntityContaineris a great machine-readable overview of the entire service. At a high level (from an entityset perspective), it corresponds with the content of the service document, which looks like this:jsonCopy{ "@odata.context": "$metadata", "@odata.metadataEtag": "...", "value": [ { "name": "Products", "url": "Products" }, { "name": "Categories", "url": "Categories" }, { "name": "Suppliers", "url": "Suppliers" } ] }Each of the objects within the value property of the service document (in the example shown) has a name and a url property. Are the url property values relative or absolute?
- Step 9
Last but certainly not least, we come to the
EntityTypeelements within theSchema. These correspond directly to the business objects, or entities, in our data model, and as such, are described using elements that reflect such detail. Let’s take one of the types as an example:xmlCopy<EntityType Name="Products"> <Key> <PropertyRef Name="ProductID"/> </Key> <Property Name="ProductID" Type="Edm.Int32" Nullable="false"/> <Property Name="ProductName" Type="Edm.String"/> <Property Name="QuantityPerUnit" Type="Edm.String"/> <Property Name="UnitPrice" Type="Edm.Decimal" Scale="variable"/> <NavigationProperty Name="Category" Type="Main.Categories" Partner="Products"> <ReferentialConstraint Property="Category_CategoryID" ReferencedProperty="CategoryID"/> </NavigationProperty> <Property Name="Category_CategoryID" Type="Edm.Int32"/> <NavigationProperty Name="Supplier" Type="Main.Suppliers" Partner="Products"> <ReferentialConstraint Property="Supplier_SupplierID" ReferencedProperty="SupplierID"/> </NavigationProperty> <Property Name="Supplier_SupplierID" Type="Edm.Int32"/> <Property Name="UnitsInStock" Type="Edm.Int32"/> <Property Name="UnitsOnOrder" Type="Edm.Int32"/> <Property Name="ReorderLevel" Type="Edm.Int32"/> <Property Name="Discontinued" Type="Edm.Boolean"/> </EntityType>The
EntityTypeclearly defines:- the individual properties and their types
- which property or properties make up the entity’s key structure
- the navigation properties, their relationship conditions, and the type of the navigation (relation)’s target
Some of the
Propertyelements have more information in further attributes (such asNullable="false"for key properties, andScale="variable"for how long the decimal place value can be).Mostly these definitions are self-explanatory, but it’s worth digging in a little to the detail of navigation properties. Let’s take the “Category” one here, and also look at the relevant part of the “Category”
EntityType:xmlCopy<Schema Namespace="Main" xmlns="http://docs.oasis-open.org/odata/ns/edm"> ... <EntityType Name="Products"> ... <NavigationProperty Name="Category" Type="Main.Categories" Partner="Products"> <ReferentialConstraint Property="Category_CategoryID" ReferencedProperty="CategoryID"/> </NavigationProperty> <Property Name="Category_CategoryID" Type="Edm.Int32"/> ... </EntityType> <EntityType Name="Categories"> <Key> <PropertyRef Name="CategoryID"/> </Key> <Property Name="CategoryID" Type="Edm.Int32" Nullable="false"/> <NavigationProperty Name="Products" Type="Collection(Main.Products)" Partner="Category"/> </EntityType> ... </Schema>If we stare at this for a moment, this relation is expressed beautifully:
textCopy+----------+ N:1 +------------+ | Products |------| Categories | +----------+ +------------+Looking at the “Products”
EntityType, we see that:- there is a
Property“Category_CategoryID” to hold the actual category foreign key - there is also a
NavigationProperty“Category” along which we can traverse the relationship with, say, the OData system query option$expand - the
ReferentialConstraintthat is contained within (and therefore qualifies) theNavigationPropertysays that the value of “Category_CategoryID” must equal the value of the property “CategoryID” in the target (“Main.Categories”)
Looking at the “Categories”
EntityType, we see that:- the “CategoryID” property is indeed the key property
- there’s a reverse
NavigationProperty“Products” but the type is a collection ofMain.Productssignifying a to-many relationship (as in “N” in the relation diagram above)
Which primitive types are used to define the properties in the "Products" entity type?
- Retrieve the Northbreeze metadata document
- Take a first look at the content
- Consider the high level XML structure
- Understand the XML namespaces
- Learn about the DataServices context
- Get acquainted with the schema element
- Take a brief look at the OData namespace
- Consider the entity container
- Take a look at the entity type definitions
- Further info