Quantcast
Channel: Category Name
Viewing all articles
Browse latest Browse all 10804

Use Singleton to define your special entity

$
0
0

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:

First, it is more straightforward in concept. Singleton is designed to present a special entity, just like company.

Second, you can directly access company from service root by querying ".svc/Company", without appending the CompanyID.

How to define and consume a 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.

In service side

 1. Define singleton in EDM model

//Define entity type

var companyType = newEdmEntityType(DefaultNamespace, "Company");

var companyId = newEdmStructuralProperty(companyType, "CompanyID", EdmCoreModel.Instance.GetInt32(false));

companyType.AddProperty(companyId);

companyType.AddKeys(companyId);

companyType.AddProperty(newEdmStructuralProperty(companyType, "Name", EdmCoreModel.Instance.GetString(true)));

companyType.AddProperty(newEdmStructuralProperty(companyType, "EmployeesCount",

EdmCoreModel.Instance.GetInt32(true)));

model.AddElement(companyType);

 

//Define singleton

EdmSingleton company = newEdmSingleton(defaultContainer, "Company", companyType);

defaultContainer.AddElement(company);

 

 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.

ODataUriParser uriParser = newODataUriParser(model, ServiceRootUri, queryUri);

ODataPath queryPath = uriParser.ParsePath();

SingletonSegment singletonSegment = queryPath.LastSegment asSingletonSegment;

 

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.

var entry = newODataEntry()

{

Properties = newList<ODataProperty>()

{

newODataProperty()

{

Name = "CompanyID",

Value = 1

},

newODataProperty()

{

Name = "Name",

Value = "Wonderland"

},

newODataProperty()

{

Name = "Revenue",

Value = 1000

}

}

};

 

ODataMessageWriterSettings writerSettings = newODataMessageWriterSettings();

writerSettings.Version = ODataVersion.V4;

writerSettings.ODataUri = newODataUri() {ServiceRoot = ServiceRootUri, Path = queryPath};

writerSettings.PayloadBaseUri = ServiceRootUri;

writerSettings.SetContentType("application/json;odata.metadata=full", Encoding.UTF8.WebName);

writerSettings.AutoComputePayloadMetadataInJson = true;

 

var message = newODataResponseMessage(stream);

 

using (var messageWriter = newODataMessageWriter(message, writerSettings, model))

{

var entryWriter = messageWriter.CreateODataEntryWriter(singletonSegment.Singleton,

singletonSegment.EdmType asEdmEntityType);

 

entryWriter.WriteStart(entry);

entryWriter.WriteEnd();

entryWriter.Flush();

}

 

In 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.

ODataMessageReaderSettings readerSettings = newODataMessageReaderSettings() {BaseUri = ServiceRootUri};

var responseMessage = newODataResponseMessage(stream);

 

using (var messageReader = newODataMessageReader(responseMessage, readerSettings, model))

{

var reader = messageReader.CreateODataEntryReader();

 

while (reader.Read())

{

switch (reader.State)

{

caseODataReaderState.EntryEnd:

ODataEntry entry = reader.Item asODataEntry;

return entry;

}

}

}

 

Sample Code Link

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.

var companyEmployeeNavigation = companyType.AddBidirectionalNavigation(newEdmNavigationPropertyInfo()

{

Name = "Employees",

Target = employeeType,

TargetMultiplicity = EdmMultiplicity.Many

}, newEdmNavigationPropertyInfo()

{

Name = "Company",

Target = companyType,

TargetMultiplicity = EdmMultiplicity.One

});

 

((EdmSingleton)company).AddNavigationTarget(companyEmployeeNavigation, employeeSet);

((EdmEntitySet)employeeSet).AddNavigationTarget(companyEmployeeNavigation.Partner, company);

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 // IncreaseRevenue is an action

                    Payload:  {"IncreaseValue":20000}


Viewing all articles
Browse latest Browse all 10804

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>