In an OData entity container, how does an entity set differ from a singleton, and when would you model a resource as a singleton?
answer
- top-level children of the container
- a collection versus exactly one
- addressed by name, no key
- 4.01 adds Nullable singletons
basics
~20 sAn OData entity set is a named top-level collection of entities addressed by key; a singleton is a named top-level single entity addressed by its name alone, suited to one-per-service resources such as the order desk's settings or the caller's own profile.
solid answer
~40 sThe `EntityContainer` holds a service's top-level resources: entity sets, singletons, action imports and function imports. An `EntitySet` names a collection of one entity type or its subtypes; that type MUST have a key, so members are found by key and the set can be queried and inserted into. A `Singleton` names exactly one entity of its type, reached from the service root by name - `/OrderDeskSettings`, say - with no key in the URL and no collection to insert into. Model a singleton when there is one instance per service, or per caller as with a `Me` resource. In OData 4.0 a singleton's `Nullable` attribute must not appear and its entity type needs a key; 4.01 allows `Nullable="true"`, letting a service support deleting or upserting it, and lets its type be key-less.
go deeper
Recall the four children of an entity container and the core contrast: an entity set is a keyed collection, a singleton is one entity reached by name with no key.
Explain the rules: an entity set's type needs a key and may hold subtypes, while a singleton needs no key in its URL and, from 4.01, may be nullable.
Show judgment about cardinality: when a keyless singleton makes URLs self-describing, and why converting a singleton into a set later breaks clients.
Treat the container as the service's published surface: every set and singleton is an entry point you support, so decide what to expose deliberately rather than mirroring storage tables.
## The entity container An OData service publishes its model's **entry points** through one **entity container**. The CSDL specification says an `EntityContainer` contains one or more of four kinds of child: - `EntitySet` - a named, top-level **collection-valued** resource. - `Singleton` - a named, top-level **single-valued** resource. - `ActionImport` - exposes an unbound action at the service root. - `FunctionImport` - exposes an unbound function at the service root. Types say what data *looks like*; the container says where it *lives*. An `Order` entity type means nothing to a client until an entity set such as `Orders` publishes instances of it. A container may also name another container in `Extends`, inheriting all of that container's children. ## Entity sets The CSDL rules for an entity set are short: - It is identified by a name that **MUST** be unique within its container. - It **MUST** specify an entity type in scope, and it **MUST** contain only instances of that type **or its subtypes** - an `Orders` set typed `Sales.Order` may hold `Sales.RushOrder` instances. - Its entity type **MAY** be abstract but **MUST** have a key, because members are told apart by key. - `IncludeInServiceDocument` (default `true`) says whether the set is listed in the service document; sets that cannot be queried without extra query options **SHOULD NOT** be listed. An entity's key is unique **within its entity set**. If two sets use the same type, the same key value in each identifies two different entities. ## Singletons A singleton is the container's answer to "there is exactly one of these": - It is identified by a name unique within the container and **MUST** specify an entity type. - It is addressed by name at the service root - `/OrderDeskSettings` - with **no key predicate**. - The protocol notes that a singleton may also be a member of an entity set; `MainSupplier` can be one of the entities in `Suppliers`. - **OData 4.01** adds `Nullable` on a singleton (default `false`; in 4.0 responses it **MUST NOT** be specified). A nullable singleton may be absent; the protocol lets a service support deleting or upserting it and says the service **SHOULD** advertise that with the Capabilities update and delete restriction annotations. - In **OData 4.01** a singleton's entity type need not declare a key; in 4.0 it must. A minimal container for an order-management service: ```xml <EntityContainer Name="SalesService"> <EntitySet Name="Customers" EntityType="Sales.Customer" /> <EntitySet Name="Orders" EntityType="Sales.Order"> <NavigationPropertyBinding Path="Customer" Target="Customers" /> </EntitySet> <Singleton Name="OrderDeskSettings" Type="Sales.DeskSettings" /> <ActionImport Name="PlaceOrder" Action="Sales.PlaceOrder" /> </EntityContainer> ``` The `NavigationPropertyBinding` tells a client that the customer reached from any order lives in `Customers`; without one, a client must assume the target set can vary per related entity. ## Choosing set or singleton | Resource in an order-management service | Model as | Why | |---|---|---| | Customers, orders, products | Entity set | Many instances, each found by key | | The order desk's configuration | Singleton | Exactly one per service | | The calling user's profile | Singleton | One per caller, no key to guess | | "Place an order" as a command | Action import | An operation, not a resource | The decision rule is cardinality from the client's point of view. If a client would always ask for "the" thing rather than "the one with key K", a singleton removes a meaningless key and makes the URL self-describing. If more than one instance could ever exist, an entity set leaves room to grow; turning a singleton into a set later changes its URL and payload shape, which existing clients notice. Per-caller resources are the other natural fit. A `Me` singleton can resolve to a different entity for each authenticated caller while the model still declares one named resource of one entity type, so the model itself does not vary by user. The alternative - an entity set the caller must query with their own key - forces every client to know an identifier the service already has, and invites requests for other callers' keys that the service must then refuse. ## OData 4.0 versus 4.01 | Aspect | OData 4.0 | OData 4.01 | |---|---|---| | Singleton `Nullable` | Must not be specified | Allowed, default `false` | | Key on a singleton's type | Required | Not required | | Entity set's type key | Required | Required | Clients that must interoperate with both versions should not assume a singleton can be deleted, and should not assume a key exists on every singleton's type.
- What does an entity container's Extends attribute do?It names another entity container in scope whose children are all added to this one. The extending container may redefine a base entity set or singleton only with an entity type derived from the base one's type; action imports and function imports cannot be redefined. It lets a service build its published surface on top of a container defined in a referenced schema.
- Can the same entity be both a singleton and a member of an entity set?Yes. The protocol says a singleton may also be a member of an entity set, so `MainSupplier` can be one of the entities in `Suppliers`. The singleton gives clients a fixed, keyless entry point to that entity; it is not a separate copy, so a change made through either address is a change to the same entity.
saying these in an interview costs you the question
- A singleton is just an entity set that happens to contain one row.
- A singleton is addressed with a key predicate such as /Settings(1).
- An entity set's entity type can never be abstract.
- An entity set may hold only its exact declared type, never subtypes.
- Every OData singleton may be deleted, whatever the protocol version.