Learn how to read OData metadata documents
Take a tour of a simple metadata document and get to know its key sections.
Overview
You will learn
- What the metadata document looks like
- What it describes
- How to navigate it
Prerequisites
Steps
Intro
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.
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 $metadata added as a further path segment:
https://odd.cfapps.eu10.hana.ondemand.com/northbreeze/$metadata
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.
Regard this drastically reduced version of the entire metadata document XML structure:
<?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 DataServices element, 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 the DataServices element 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.
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 edmx part 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 xmlns attributes, which are either in the pure xmlns form, or in a xmlns:prefix form. 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 as edmx: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:
<?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/edmx | edmx | Edmx, Reference, Include, DataServices |
http://docs.oasis-open.org/odata/ns/edm | (default) | Schema, EntityContainer, EntitySet, EntityType etc |
As the primary area of interest in such resources is what’s in the DataServices section (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).
To understand the context of the DataServices element, 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:Schema element.
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 Schema element, 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:
+------+
| 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 EntityContainer and EntityType elements. Let’s take these one at a time to round out our brief look at the metadata document.
Before we do, we should make a note of one more thing at this level, and that’s the Namespace attribute in the <Schema> element:
<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 Namespace attribute is Main (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 Main OData namespace is used. Here’s another drastically reduced version of the entire XML document, showing where Main is found:
<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 Main namespace 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” EntityType we 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
The EntityContainer element within the Schema represents 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 EntityType upon which an EntitySet is based, these are declared in that definition. For example, the “Products” EntityType has relationships with “Categories” and “Suppliers”, as declared with the NavigationPropertyBinding elements within the “Products” EntitySet:
<EntitySet Name="Products" EntityType="Main.Products">
<NavigationPropertyBinding Path="Category" Target="Categories"/>
<NavigationPropertyBinding Path="Supplier" Target="Suppliers"/>
</EntitySet>Thus the EntityContainer is 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:
{
"@odata.context": "$metadata",
"@odata.metadataEtag": "...",
"value": [
{
"name": "Products",
"url": "Products"
},
{
"name": "Categories",
"url": "Categories"
},
{
"name": "Suppliers",
"url": "Suppliers"
}
]
}Last but certainly not least, we come to the EntityType elements within the Schema. 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:
<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 EntityType clearly 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:
<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:
+----------+ 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)
Resources
Discussion
Share feedback on this tutorial or join the conversation in SAP Community.