[Tutorial & Sample] Use Singleton to define your special entity


Ever had a special entity where there can be only one of its kind, but bothered by having to define a one-element entity set for it? Ever wanted to request a special entity but bothered by needing to find out its key first? Use a singleton! Singleton is newly introduced in OData V4, to allow developers name such special entity, and it can be addressed directly by its name from the service root.

Let’s think about a universal scenario which can benefit from singleton:

We want to have a model to present the staff information of a company.

So first, we define an EntityType named EmployeeType to represent the schema of an employee information, and accordingly define EmployeeSet (which is an EntitySet) to actually have the information of each employee.

And second, we also want to have an entity to present the information of the company, like company name, logo, strategy etc. First step is to define an EntityType named CompanyType of cause, what about then, define an EntitySet named CompanySet? EntitySet means a collection of entities, but we only need one entity for company! Of cause you can have just one entity in the EntitySet, like what we did before V4. But to have one entity, you are forced to have a collection of entities! Singleton in V4 can release you from such an awkward situation.

Defining company as a singleton at least have 2 advantages than defining company as an EntitySet:

  • It is more straightforward in concept. Singleton is designed to present a special entity, just like company.
  • You can directly access company from service root by querying “.svc/Company”, without appending the CompanyID.

How to define and consume Singleton

Just little effort is needed for a service to support singleton. Basically, Singleton is quite similar with EntitySet, and the biggest difference of singleton and entityset is that when writing a singleton, we call CreateODataEntryWriter, rather than CreateODataFeedWriter for writing EntitySet. Same to call CreateODataEntryReader for reading a singleton.

Following shows the simple steps to support singleton (Sample Code).

Service side

1. Define singleton in EDM model

2. Parse singleton segment in querying URI

When receiving a query uri, like “.svc/Company”, service calls ODataUriParser to parse the uri, and in this case the last segment of the uri should be SingletonSegment.

3. Write a singleton

To write the response, service calls CreateODataEntryWriter to write the company info in json payload. To simply the example, we directly write the payload into a stream.

Client side

After sending the query “.svc/Company”, client can receive a response from wire if everything works well. So client just need to call CreateODataEntryReader to read the singleton out.

We have response in the stream in this example.

Singleton advanced features

The example above shows the simplest way to use a singleton, but there are some other advanced features of singleton:

1. Query singleton with query option

Singleton is an entity after all, so only $select and $expand are supported when singleton is the resource path.

Sample Uri:

.svc/Company?$select=Name

2. Navigation

  • Singleton can have EntitySet, contained EntitySet or singleton as navigation property.
  • Entityset can have singleton as navigation property

Below is a code snippet to define navigation of singleton.

Sample Uri:

.svc/Company/Employees

.svc/Company?$expand=Employees

.svc/Employees(1)/Company

3. Bound Action/Function

Since bound action and function is defined on EntityType, singleton can inherited action and function from its defining EntityType.

Sample Uri:

GET .svc/Company/NameSpace.GetEmployeesCount() // GetEmployeesCount is a function

POST .svc/Company/NameSpace.IncreaseRevenue with payload:  {“IncreaseValue”:20000}  // IncreaseRevenue is an action

Comments (6)

  1. maxvella says:

    I understand that this will require version 6.0+ of the OData Client Library since V4 is not supported by the earlier releases, but what about the server bits? To my knowledge the OData V4.0 Server bits have not yet been released. Can you please provide some guidance as to which versions we need to use? In reality it would help if the OData team could issue a road map for the WCF Data Services stack. Thanks

  2. Zoe Luo says:

    Sorry, we do not plan to release WCF Data Services in V4. But instead we will release WebApi version for service bits. We already have prerelease webapi.odata at http://www.myget.org/…/aspnetwebstacknightly. You can have a try or you can have your own implementation of service with ODataLib API. Thanks

  3. maxvella says:

    Thank you that clarifies.

  4. George says:

    Does this mean the WCF Data Services team has no plans to support OData v4?  Is there an official word on this?

  5. Jan says:

    ++George Where are the enums or at least where is a Roadmap / state of implementation design.

    Id hate to start a new Project and rewrite the communication layer if dataservices are ready in 3 month.

  6. Stephen says:

    >>Sorry, we do not plan to release WCF Data Services in V4.

    Does this mean that WCF Data Services is done?  No more development?  If so that is sad because:

    1. I should not find out on a blog comment.  I have put a lot of work into using WCF Data Services.  It is kind of a slap in the face that you could not even say that it is dead in a full post.

    2. It is a great product that works well.  Why kill it off.  (But then, we ask that question about all the techs that Microsoft kills off.)