In an OData metadata document, how does a vocabulary annotation apply a term to a model element, and what does Core.Computed tell a client?
answer
- terms live in vocabularies
- reference, include, alias
- nested or externally targeted
- a qualifier for a second application
- Tag terms default to true
basics
~20 sAn OData annotation applies a vocabulary term to a model element, nested inside it or targeted from an Annotations block, with an optional qualifier. Core.Computed marks a property the service generates on insert and update; a value the client sends is ignored.
solid answer
~40 sA **vocabulary** is a CSDL schema of **terms**; the metadata document brings one into scope with `edmx:Reference` and `edmx:Include`, usually with an alias such as `Core`. An `Annotation` names a `Term`, takes its value from a constant or a path expression, and reaches its target either by nesting inside the model element or from an `Annotations Target="..."` block; a `Qualifier` lets the same term apply more than once, for example per device. `Core.Computed` is a `Core.Tag` term whose default value is true: the service generates the value on insert and update, and the protocol says a computed value sent by the client MUST be ignored. Clients SHOULD ignore terms they do not know, and a service MUST NOT require them to understand custom annotations.
code
xml · 22 lines<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.01">
<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:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Sales">
<EntityType Name="Order">
<Key><PropertyRef Name="ID"/></Key>
<Property Name="ID" Type="Edm.Int32" Nullable="false"/>
<Property Name="CreatedAt" Type="Edm.DateTimeOffset">
<Annotation Term="Core.Computed"/>
</Property>
<Property Name="Channel" Type="Edm.String">
<Annotation Term="Core.Immutable"/>
</Property>
</EntityType>
<Annotations Target="Sales.Order/Channel">
<Annotation Term="Core.Description" Qualifier="Short" String="Sales channel"/>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>go deeper
Recall that annotations add meaning to the model and that the Core vocabulary holds basic terms such as Description, Computed and Immutable.
Explain term, target and qualifier, nested versus externally targeted annotations, and why a bare Core.Computed annotation evaluates to true.
Show how a generic client turns Core terms into behaviour, such as read-only fields and ETag-guarded writes, while ignoring terms it does not recognise.
Decide which semantics belong in shared vocabularies versus a private one, and how annotation changes are governed so that clients ignoring them still work.
## Vocabularies, terms and annotations OData metadata is extensible through **vocabularies**. A vocabulary is a CSDL schema that contains **terms**; each term is a named metadata extension with a type. An **annotation** applies a term to a model element (a schema, an entity type, a property, an entity set, an action or function, a parameter) and supplies the value of that application. The OData technical committee publishes shared vocabularies, among them **Core** (`Org.OData.Core.V1`, usually aliased `Core`) and **Capabilities** (`Org.OData.Capabilities.V1`), and anyone can define a vocabulary for a scenario of their own. ## Bringing a vocabulary into scope Both the term and the annotated element MUST be in scope. A metadata document references the vocabulary's CSDL document and includes its namespace: - in CSDL XML, `edmx:Reference Uri="..."` containing `edmx:Include Namespace="Org.OData.Core.V1" Alias="Core"`; - in CSDL JSON, a `$Reference` entry whose `$Include` lists `$Namespace` and `$Alias`. The alias is a document-local shorthand, so `Core.Description` and `Org.OData.Core.V1.Description` name the same term. ## Applying a term: term, target, value, qualifier 1. **Term**: `Term="Core.Description"` in XML, or a member named `"@Core.Description"` in JSON. 2. **Target**: implicit, by nesting the annotation inside the element it annotates, or explicit through **external targeting**: an XML `Annotations Target="Sales.Customer"` block, or a JSON `$Annotations` member keyed by the target path. External targeting lets an annotation live in a different schema, or a different document, from the element it describes. 3. **Value**: a constant expression (`String="..."`, `Bool="false"`) or a dynamic one such as a `Path` to a property. With no expression, a term of primitive type evaluates to the term's `DefaultValue`. 4. **Qualifier**: an optional simple identifier (`Qualifier="Tablet"`, or `#Tablet` in JSON) so that one term can be applied several times to the same element. Target, term and qualifier together identify exactly one annotation, and an element MUST NOT carry two annotations with the same term and qualifier. A term's definition may list where it applies (`AppliesTo`), but clients SHOULD be prepared for any term on any element. ## Core terms a client acts on Many Core terms have the type `Core.Tag`, a Boolean whose `DefaultValue` is `true`, so a bare `<Annotation Term="Core.Computed"/>` means true. | Core term | Applies to | What it tells a client | |---|---|---| | `Description`, `LongDescription` | most elements | human-readable text for documentation and tooltips | | `Computed` | property | the value is generated on both insert and update | | `Immutable` | property | a client may supply the value on insert; it remains unchanged on update | | `Permissions` | properties, types, entity sets, operations | flags `None`, `Read`, `Write`, `ReadWrite`, `Invoke` | | `OptimisticConcurrency` | entity set | data modification requires ETags; lists the properties the ETag is computed from | | `SchemaVersion` | schema, reference | the version of a schema, for version-specific requests | The protocol gives `Computed` teeth. When an entity is created, computed properties can be omitted and MUST be ignored if included. On update, key and read-only properties, computed ones included, can be omitted, and a value sent for one MUST be ignored. A generated form should therefore show computed fields as read-only rather than let users type values that silently vanish. ## Rules that keep annotations safe - A service MUST NOT require a client to understand custom annotations to interpret a response, and the minimal conformance level forbids requiring clients to understand any metadata or instance annotations. - Clients SHOULD ignore unknown or invalid terms and treat invalid values as unknown; such annotations should never cause an error while the payload stays well formed. - An **instance annotation** in a payload overrides the same annotation made in metadata. - A derived type's annotation replaces, rather than merges with, its base type's annotation for the same term and qualifier. - A client can state which annotations it wants with the `odata.include-annotations` preference, which applies to metadata requests as well as data; the service MAY ignore it.
- How do Core.Immutable and Core.Computed differ for a client building OData create and edit forms?`Core.Immutable` means the client may supply the value on insert and it then stays unchanged on update, so the field is editable on the create form and read-only on the edit form. `Core.Computed` means the service generates the value on insert and update, so the field is read-only on both; values sent for it are ignored.
- Why would an OData model be annotated from a separate schema or document through external targeting?External targeting lets an annotation sit outside the element it describes, so a UI layer or a vocabulary-specific document can annotate a model it does not own. The `Annotations` block names the target by path, and in CSDL XML a referencing document can pull those annotations in with `edmx:IncludeAnnotations`, filtered by term namespace, qualifier or target namespace.
saying these in an interview costs you the question
- OData annotations are comments and never change protocol behaviour.
- An unknown annotation term is an error the client must report.
- A term can be applied only once to any model element.
- Sending a value for a Core.Computed property makes the request fail.
- Core.Immutable means a client can never set the property, not even on insert.
- An annotation must live in the same schema as the element it targets.