Skip to content

Conventions for OData Metadata

CSDL XML Metadata

The service generator tool requires as input an OData Common Schema Definition Language (CSDL) XML metadata file (for OData version 2.0 or 4.0). OData version 4.0 is recommended, unless it is necessary to accommodate clients that use pre-4.0 OData frameworks.

The metadata in the CSDL XML document defines a data model for the business objects upon which the OData service will operate.

The following conventions facilitate the generation and deployment of OData services that are compatible with the Server OData API (the Java class library that supports the implementation of the generated OData services), as well as to ensure the smooth interoperability of the generated services with a variety of OData client frameworks and SDKs.

  • Use the file extension .csdl.xml for OData CSDL XML files. When using SAP Business Application Studio, files with this extension can be viewed or edited with the graphical CSDL Editor, accessed via the context menu.

  • For OData 4.0 models, include the xmlns:xsi and xsi:schemaLocation attributes in the edmx:Edmx root element, as shown in the following example, to enable enhanced CSDL editing if you have installed the XML Language Support by Red Hat extension for Visual Studio Code.

  • For the Schema Namespace, consider using Java package naming conventions or .NET Namespace Conventions.

  • For the EntityContainer Name, provide a name that describes the service, such as BankService, ShopService etc.

  • Use Upper Camel Case for naming types and properties, e.g. TravelAgency.

  • Use singular names for complex/entity types, e.g. Address, Customer.

  • Use plural names for entity sets, e.g. Customers, or use the Set suffix, e.g. CustomerSet.

  • Avoid using property/type names that differ only in case (e.g. customer and Customer) or that differ only in the absence/presence of underscores (e.g. Customer and _Customer).

  • For key property names, use the ID suffix appended to the entity type name, e.g. CustomerID for entity type Customer.

  • To support automatic server-side key generation for primary keys, it is recommended that you use non-composite numeric keys of type Edm.Int64. If you are certain that 32-bit integer keys are sufficient, then use Edm.Int32. If in any doubt, then use 64-bit integer keys. You can also use type Edm.Decimal for key properties, but is likely to use more space in the database than Edm.Int64.

  • You can also use the Edm.Guid and Edm.String key types, but they are not recommended because they will take up more space within the database. If you use type Edm.String, then specify MaxLength="36" to ensure that the key column will be large enough to contain a generated GUID. String-typed properties containing database-generated sequence numbers are not supported.

  • Properties of type Edm.Binary and Edm.String should include the MaxLength facet unless they are intentionally of unbounded length. This ensures an optimal selection of database column type (e.g. varbinary versus blob, varchar versus clob). It is assumed that MaxLength for strings specifies the number of Unicode code points, which may result in 4*MaxLength being used as a database column length if the database uses UTF-8 column encoding.

  • Properties of type Edm.Decimal should specify Scale and Precision facets. This ensures an optimal selection of database column type. Note that an unspecified scale defaults to zero (only integer values can be stored in the database column if Scale is unspecified).

  • Use an explicit Nullable facet for properties. Since the default for OData CSDL XML is Nullable="true", it is easy to accidentally have nullable properties. Accidental nullability of properties may be a burden to client application developers, especially when using languages such as Kotlin and Swift that have strong support for nullable types. It may result in client developers having to defensively program against the possibility of properties having null values when it was not intended.

  • Primary keys embedded within complex-typed properties are not currently supported.

  • Foreign keys embedded within complex-typed properties are not currently supported.

  • Stream properties embedded within complex-typed properties are not currently supported.

  • Navigation properties embedded within complex-typed properties are not currently supported.

  • Bidirectional relationships (with navigation properties in both directions) are preferred.

  • Foreign keys (specified with ReferentialConstraint) should be used wherever applicable. This permits the automatic implementation of OData features such as: $expand queries, deep insert, bind operations, and link operations.

  • Use OnDelete Action="Cascade" for navigation properties where the deletion of a parent entity should cascade to automatic deletion of the related child entities.

  • Use OnDelete Action="None" for navigation properties where the deletion of a parent entity should be restricted (disallowed) when there are still existing related child entities.

  • Use the Core.Immutable annotation for any properties that cannot be changed after an entity is created. See Customer and DateOfBirth in the example below.

  • Use Validation annotations to express simple declarative validation rules. See Order/Quantity in the example below. Currently, such validation annotations might be utilized by client frameworks, but the server runtime does not itself enforce them. Use entity listeners for server-side enforcement of validation rules.

Example Document

<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://docs.oasis-open.org/odata/ns/edmx http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edmx.xsd http://docs.oasis-open.org/odata/ns/edm http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edm.xsd">
    <edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml">
        <edmx:Include Namespace="Org.OData.Core.V1" Alias="Core"/>
    </edmx:Reference>
    <edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Validation.V1.xml">
        <edmx:Include Namespace="Org.OData.Validation.V1" Alias="Validation"/>
    </edmx:Reference>
    <edmx:DataServices>
        <Schema Namespace="example" xmlns="http://docs.oasis-open.org/odata/ns/edm" Alias="Self">
            <ComplexType Name="Address">
                <Property Name="Number" Type="Edm.String" MaxLength="100" Nullable="true"/>
                <Property Name="Street" Type="Edm.String" MaxLength="100" Nullable="true"/>
                <Property Name="City" Type="Edm.String" MaxLength="100" Nullable="false"/>
                <Property Name="Region" Type="Edm.String" MaxLength="100" Nullable="true"/>
                <Property Name="Country" Type="Edm.String" MaxLength="100" Nullable="true"/>
                <Property Name="PostalCode" Type="Self.PostalCode" Nullable="true"/>
            </ComplexType>
            <ComplexType Name="PostalCode">
                <Property Name="AreaCode" Type="Edm.String" MaxLength="2" Nullable="false"/>
                <Property Name="DistrictCode" Type="Edm.String" MaxLength="2" Nullable="false"/>
                <Property Name="SectorCode" Type="Edm.String" MaxLength="1" Nullable="false"/>
                <Property Name="UnitCode" Type="Edm.String" MaxLength="2" Nullable="false"/>
            </ComplexType>
            <EntityType Name="Customer">
                <Annotation Term="Core.Description" String="Customer entity type"/>
                <Key>
                    <PropertyRef Name="CustomerID"/>
                </Key>
                <Property Name="CustomerID" Type="Edm.Int64" Nullable="false">
                    <Annotation Term="Core.Description" String="Customer primary key"/>
                </Property>
                <Property Name="Name" Type="Edm.String" MaxLength="100" Nullable="false"/>
                <Property Name="HomeAddress" Type="Self.Address" Nullable="false"/>
                <Property Name="WorkAddress" Type="Self.Address" Nullable="true"/>
                <Property Name="PlaceOfWork" Type="Edm.String" MaxLength="100" Nullable="false"/>
                <Property Name="DateOfBirth" Type="Edm.Date" Nullable="false">
                    <Annotation Term="Core.Immutable"/>
                </Property>
                <NavigationProperty Name="Orders" Type="Collection(Self.Order)" Partner="Customer">
                    <OnDelete Action="Cascade"/>
                </NavigationProperty>
            </EntityType>
            <EntityType Name="Order">
                <Annotation Term="Core.Description" String="Order entity type"/>
                <Key>
                    <PropertyRef Name="OrderID"/>
                </Key>
                <Property Name="OrderID" Type="Edm.Int64" Nullable="false">
                    <Annotation Term="Core.Description" String="Order primary key"/>
                </Property>
                <Property Name="CustomerID" Type="Edm.Int64" Nullable="true"/>
                <Property Name="Product" Type="Edm.String" MaxLength="100" Nullable="false"/>
                <Property Name="Quantity" Type="Edm.Int32" Nullable="false">
                    <Annotation Term="Validation.Minimum" Decimal="1"/>
                </Property>
                <NavigationProperty Name="Customer" Type="Self.Customer" Nullable="true" Partner="Orders">
                    <ReferentialConstraint Property="CustomerID" ReferencedProperty="CustomerID"/>
                </NavigationProperty>
            </EntityType>
            <EntityContainer Name="ExampleService">
                <EntitySet Name="Customers" EntityType="Self.Customer">
                    <Annotation Term="Core.Description" String="Customers entity set"/>
                    <NavigationPropertyBinding Path="Orders" Target="Orders"/>
                </EntitySet>
                <EntitySet Name="Orders" EntityType="Self.Order">
                    <Annotation Term="Core.Description" String="Orders entity set"/>
                    <NavigationPropertyBinding Path="Customer" Target="Customers"/>
                </EntitySet>
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

Annotation Terms

OData 4.0 defines various standard annotation terms such An annotation term as the Core.Description term, which can be used to annotate any CSDL metadata element with a description.

In general, annotation terms provide for metadata extensibility.

Standard annotation term definitions are grouped together in standard annotation vocabularies.

Custom Vocabularies

The service generator tool defines various custom annotation vocabularies. Each custom vocabulary defines a number of annotation terms. You can use these custom annotation terms to annotate CSDL model elements to enable various features for the generated OData service.

The following sections describe each of the custom annotation vocabularies.

Note

All examples use OData 4.0 syntax, but the service generator tool allows OData 4.0 annotations to be used within CSDL XML files for all supported OData versions (2.0, 3.0, and 4.0).

Note

All custom annotation terms defined by the following vocabularies that can be applied to an entity type can also be applied (instead) to an entity set. OData permits multiple entity sets to share the same entity type. However such sharing of an entity type by multiple entity sets is uncommon in practice, so it is recommended to annotate entity types rather than annotating entity sets.

Cache Vocabulary

To use terms within the Cache vocabulary include a Reference element for the com.sap.cloud.server.odata.cache.v1 namespace. This vocabulary defines terms for configuration of caching within a cache databases.

Example:

<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://docs.oasis-open.org/odata/ns/edmx http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edmx.xsd http://docs.oasis-open.org/odata/ns/edm http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edm.xsd">
    <edmx:Reference Uri="vocabularies/com.sap.cloud.server.odata.cache.v1.xml">
        <edmx:Include Namespace="com.sap.cloud.server.odata.cache.v1" Alias="Cache"/>
    </edmx:Reference>
    ...
</edmx:Edmx>

Security Vocabulary

To use terms within the Security vocabulary include a Reference element for the com.sap.cloud.server.odata.security.v1 namespace. This vocabulary defines terms for annotating elements with required security roles.

Example:

<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://docs.oasis-open.org/odata/ns/edmx http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edmx.xsd http://docs.oasis-open.org/odata/ns/edm http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edm.xsd">
    <edmx:Reference Uri="vocabularies/com.sap.cloud.server.odata.security.v1.xml">
        <edmx:Include Namespace="com.sap.cloud.server.odata.security.v1" Alias="Security"/>
    </edmx:Reference>
    ...
</edmx:Edmx>

SQL Vocabulary

To use terms within the SQL vocabulary include a Reference element for the com.sap.cloud.server.odata.sql.v1 namespace. This vocabulary defines terms relating to the underlying SQL database used by the generated OData service for entity storage.

Example:

<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://docs.oasis-open.org/odata/ns/edmx http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edmx.xsd http://docs.oasis-open.org/odata/ns/edm http://docs.oasis-open.org/odata/odata/v4.0/os/schemas/edm.xsd">
    <edmx:Reference Uri="vocabularies/com.sap.cloud.server.odata.sql.v1.xml">
        <edmx:Include Namespace="com.sap.cloud.server.odata.sql.v1" Alias="SQL"/>
    </edmx:Reference>
    ...
</edmx:Edmx>

Last update: November 18, 2021