skip to content

In OData's entity data model, how is a relationship like Order-to-Customer declared, and what do Partner and navigation property bindings tell a client?

level: middleimportance: should knowfreq 14%

answer

  1. a property typed as another entity
  2. single-valued or Collection(...)
  3. Partner: the declared way back
  4. binding: which entity set holds targets
  5. omitted means assume nothing

basics

~20 s

An OData relationship is a NavigationProperty typed as another entity type or a collection of it. Partner names the inverse property that leads back; a NavigationPropertyBinding on the entity set says which entity set holds the related entities.

solid answer

~40 s

On `Order`, a `NavigationProperty` named `Customer` has type `Sales.Customer` - single-valued, `Nullable` defaulting to true; on `Customer`, `Orders` has type `Collection(Sales.Order)`, which never takes `Nullable` because a collection may be empty. Setting `Partner` on each to the other declares one bidirectional relationship: following `Customer` from an order and then `Orders` must lead to a collection containing that order. Without `Partner`, a client can assume nothing about a way back. Types alone do not say where related entities live, so the `Orders` entity set carries a `NavigationPropertyBinding` with `Path="Customer"` and `Target="Customers"`; if a binding is omitted, clients MUST assume the target set can vary per related entity. A `ReferentialConstraint` can tie `Order.CustomerID` to `Customer.ID`, and `OnDelete` states what deleting the source entity does to related ones.

go deeper

for a junior

Recall that relationships are navigation properties typed as another entity type, either single-valued or Collection(...), and that Partner names the property leading back.

for a middle

Explain the split of duties: the property's type says what is related, Partner says the relationship is bidirectional, and a navigation property binding says which entity set holds the targets.

for a senior

Show what goes wrong without the declarations: clients that cannot locate related entities' sets, guessed inverses, and deletes whose effect on related entities is unpredictable.

for a principal

Treat completeness of the relationship declarations as part of the API's contract: generic tooling is only as good as the partners, bindings and constraints the model states.

## Navigation properties In OData's entity data model a **relationship** is not a separate element; it is a **navigation property** on a structured type, whose type is another entity type: - **Single-valued**: `Type="Sales.Customer"` - at most one related entity. `Nullable` (default `true`) says whether there may be none; `Nullable="false"` means every order **MUST** have a customer. - **Collection-valued**: `Type="Collection(Sales.Order)"` - any number of related entities. `Nullable` **MUST NOT** be specified, because a collection may simply be empty. - Related entities **MUST** be of the declared type or one of its subtypes; the type may also be the abstract `Edm.EntityType`. - A collection-valued navigation property may be annotated `Core.Ordered` to promise a stable order. ## Partner: a declared inverse `Partner` names the navigation property on the target type that leads back. The CSDL rules: 1. The partner is a path relative to the target entity type; it may traverse complex properties but **MUST NOT** traverse navigation properties. 2. Its type **MUST** be the declaring entity type (or one of its parent types). 3. If the partner is single-valued, it **MUST** lead back to the source entity from every related entity; if it is collection-valued, the source entity **MUST** be in that collection. 4. The partner **MUST** either name the current property as its own partner - a true **bidirectional** relationship - or declare no partner. 5. Navigation properties of **complex types MUST NOT** specify a partner. If no partner is declared, "no assumptions can be made" about a way back, even when a plausibly named property exists on the target. A client building a two-way view, or keeping both sides of a relationship in step after an edit, needs `Partner` to know the two properties describe one relationship. ## Navigation property bindings: from types to entity sets A navigation property's type says *what* the related entity is, not *where* it lives - the same `Customer` type could back `Customers` and `ArchivedCustomers`. An entity set or singleton therefore carries **navigation property bindings**: - `Path` names a navigation property of the set's entity type (possibly via type casts, complex properties or containment navigation properties). - `Target` names the entity set or singleton that holds the related entities. - A set **SHOULD** bind every navigation property of its type. If a binding is omitted, clients **MUST** assume the target set can vary per related entity. - The same path **MUST NOT** appear in more than one binding: a binding asserts that all related entities come from a single set. Without a binding, a generic client cannot know from the model which set's rules, capabilities or canonical addresses apply to a related entity, and a response describes such entities by their type rather than by an entity set. ## Referential constraints and on-delete actions A single-valued navigation property **MAY** declare a `ReferentialConstraint`: the dependent property on the declaring type (`Order.CustomerID`) **MUST** have the same value as the principal property on the target (`Customer.ID`). That lets clients see that a foreign-key-like property and the navigation agree. A navigation property **MAY** also declare `OnDelete`, describing what the service does to related entities when the source entity is deleted: | `Action` value | Effect on related entities | |---|---| | `Cascade` | They are deleted with the source entity | | `None` | A DELETE of a source entity that has related entities fails | | `SetNull` | Dependent properties tied by a referential constraint are set to null | | `SetDefault` | Those dependent properties are set to their default values | Without `OnDelete`, the CSDL says the service's behaviour "is not predictable by the client and could vary per entity". ## Putting it together ```xml <EntityType Name="Order"> <Key><PropertyRef Name="ID" /></Key> <Property Name="ID" Type="Edm.Int32" Nullable="false" /> <Property Name="CustomerID" Type="Edm.String" Nullable="false" /> <NavigationProperty Name="Customer" Type="Sales.Customer" Nullable="false" Partner="Orders"> <ReferentialConstraint Property="CustomerID" ReferencedProperty="ID" /> </NavigationProperty> </EntityType> <EntityType Name="Customer"> <Key><PropertyRef Name="ID" /></Key> <Property Name="ID" Type="Edm.String" Nullable="false" /> <NavigationProperty Name="Orders" Type="Collection(Sales.Order)" Partner="Customer" /> </EntityType> ``` With `Orders` and `Customers` entity sets each binding its navigation property to the other, a client knows the shape of the relationship, both directions, the property that mirrors the customer's key and the set every related entity lives in - without reading a line of documentation.

  • What does a generic client lose when an entity set omits a navigation property binding?
    It must assume each related entity may come from a different entity set, so it cannot apply one set's rules or capabilities to the related entities ahead of time. Responses then describe those entities by type rather than by entity set, and the client depends on per-entity information in payloads. The CSDL therefore says a set SHOULD bind every navigation property of its type.
  • What does OnDelete declare, and what happens when it is absent?
    It states what the service does to related entities when the source entity is deleted: `Cascade` deletes them, `None` makes the DELETE fail while related entities exist, and `SetNull` or `SetDefault` reset dependent properties tied by a referential constraint. Without it, the CSDL says the service's behaviour is not predictable by the client and may vary per entity.

saying these in an interview costs you the question

  • Every navigation property must declare a Partner, or the model is invalid.
  • A collection-valued navigation property should be Nullable="false" to forbid empty lists.
  • The navigation property's type tells a client which entity set holds the related entities.
  • A navigation property on a complex type can declare a Partner like any other.
  • Without OnDelete, deleting a customer always cascades to its orders.