Skip to content

OData Singletons

Introduction to Singletons

Singletons are named entities that can be accessed as direct children of the entity container defined in the OData 4.0 and newer specifications. Offline OData has supported the OData singletons since SAP BTP SDK for Android 24.4.0 and SAP BTP SDK for iOS 24.4.0. Depending on the OData version and the back-end specific implementations, the HTTP response for a singleton instance may or may not contain the key properties.

We recommend using the SAP Cloud Application Programming Model to try out the singleton feature.

To download the singletons from the back-end, add a defining query for the singleton and perform the download.

Modification of singletons is carried out by utilizing the updateEntity() method as usual. The one difference involves creating a singleton request, as explained in the create singleton section, below.

Add Defining Query For The Singleton

Adding a defining query for a singleton follows the same procedure as adding a defining query for other entity sets. The example below showcases how to add a defining query for a singleton named S1.

// add a new defining query for Singleton S1
OfflineODataDefiningQuery s1Query = new OfflineODataDefiningQuery("reqS1", "S1", false);
offlineODataProvider.addDefiningQuery(s1Query);
// add a new defining query for Singleton S1
var s1Query = OfflineODataDefiningQuery("reqS1", "S1", false)
offlineODataProvider.addDefiningQuery(s1Query);
// add a new defining query for Singleton S1
let s1Query = OfflineODataDefiningQuery(name: "reqS1", query: "S1", automaticallyRetrievesStreams: false)
offlineODataProvider.addDefiningQuery(definingQuery: s1Query)

Note

The automaticallyRetrievesStreams parameter for the OfflineODataDefiningQuery may be set to true only if the singleton has the stream property.

Creating The Singleton

Similar to the widely used singleton design pattern in software engineering, the OData singleton is usually used as a predefined single-valued instance for a give entity type across the OData back-end service. Client applications commonly access the singleton by downloading the singleton instance from the back-end service with the defining query. In instances where the singleton needs to be generated from the client side, the createEntity() method is not expected to create the singleton. This is because the singleton can be addressed directly by its name without specifying the keys of its underlying entity type. The Upsert an Entity section in the OData Specification states that a singleton can be upserted with an update request if it does not already exist.

The example below illustrates how to create the singleton named S1 using an UPDATE request..

// upsert singleton S1
EntitySet s1Set = dataService.getSingleton("S1");
EntityType s1Type = t1Set.getEntityType();
Property s1pk = t1Type.getProperty("pk");
EntityValue entityValue = EntityValue.ofType(s1Type);
entityValue.setEntitySet(s1Set);
s1pk.setInt(entityValue, 1);
RequestOptions requestOptions = new RequestOptions();
requestOptions.setUpdateMode(UpdateMode.REPLACE);
dataService.updateEntity(entityValue, HttpHeaders.empty, requestOptions);
// upsert singleton S1
var s1Set = dataService.getSingleton("S1");
val s1Type: EntityType = s1Set.getEntityType()
val s1pk = s1Type.getProperty("pk")
val entityValue = EntityValue.ofType(s1Type)
entityValue.setEntitySet(s1Set)
s1pk.setInt(entityValue, 1)
val requestOptions = RequestOptions()
requestOptions.setUpdateMode(UpdateMode.REPLACE)
dataService.updateEntity(entityValue, HttpHeaders.empty, requestOptions);
// upsert singleton S1
let s1Set: EntitySet = dataService.entitySet(withName: "S1")
let s1Type: EntityType = s1Set.entityType
let s1Pk = s1Type.property(withName: "pk")
let entityValue = EntityValue.ofType(s1Type)
entityValue.entitySet = s1Set
s1Pk.setIntValue(in: entityValue, to: 1)
let requestOptions: RequestOptions = RequestOptions()
requestOptions.updateMode = UpdateMode.replace
try dataService.updateEntity(entityValue, headers: HTTPHeaders.empty, options: requestOptions)

Note

Another reason to refrain from using createEntity() with singletons is the potential for certain back ends to specifically disable POST requests to singletons. If the back end has been constructed using the SAP Cloud Application Programming Model, we advise that you review the restrictions for creating singletons.

Query The Singleton

As describe in the OData Protocol, singletons are single-valued resources at the top level and can be directly addressed by their names. The example below illustrates how to read a singleton named S1. The OData API uses a dedicated entity set for each singleton and expects a single entity value response for the singleton query.

EntitySet s1Set = dataService.getSingleton("S1");
DataQuery s1Query = new DataQuery().from(s1Set);
EntityValue entityValue = dataService.executeQuery(s1Query).getRequiredEntity();
//...
var s1Set = dataService.getSingleton("S1");
var s1Query = DataQuery().from(s1Set);
var entityValue = dataService.executeQuery(s1Query).getRequiredEntity();
//update the properties of the entity value
let s1Set: EntitySet = dataService.entitySet(withName: "S1")
let s1Query = DataQuery().from(s1Set)
let entityValue = try dataService.executeQuery(s1Query).requiredEntity()
//...

If the client application is generated by the SAP BTP SDK Assistant for iOS, then the generated proxy classes for the singleton can be used to simplify the query.

Querying the singleton with the ilodata command line utility is also supported as of SAP BTP SDK for Android 24.4.0 and SAP BTP SDK for iOS 24.4.0. The following is a sample ilodata command to query the singleton named S1.

ILOData > get S1

Update The Singleton

If the singleton instance already exists, then there is no need to address the upsert. The singleton can be updated with updateEntity() as usual. The sample below demonstrates usage of updateEntity() for the regular update of the singleton entity.

The sample below shows how to create the singleton named S1 using an update request.

DataQuery s1Query = new DataQuery().from(s1Set);
EntityValue entityValue = dataService.executeQuery(s1Query).getRequiredEntity();
//update the properties of the entity value
//...

// update singleton S1
dataService.updateEntity(entityValue);
var s1Query = DataQuery().from(s1Set);
var entityValue = dataService.executeQuery(s1Query).getRequiredEntity();
//update the properties of the entity value
//...

// update singleton S1
dataService.updateEntity(entityValue);
let s1Query = DataQuery().from(s1Set)
let entityValue = try dataService.executeQuery(s1Query).requiredEntity()
//update the properties of the entity value
//...

// update singleton S1
try dataService.updateEntity(entityValue)

Delete The Singleton

The sample below shows how to delete the singleton named S1 using the delete request.

DataQuery s1Query = new DataQuery().from(s1Set);
EntityValue entityValue = dataService.executeQuery(s1Query).getRequiredEntity();
// delete singleton S1
dataService.deleteEntity(entityValue);
var s1Query = DataQuery().from(s1Set);
var entityValue = dataService.executeQuery(s1Query).getRequiredEntity();
// delete singleton S1
dataService.deleteEntity(entityValue);
let s1Query = DataQuery().from(s1Set)
let entityValue = try dataService.executeQuery(s1Query).requiredEntity()
// delete singleton S1
try dataService.deleteEntity(entityValue)

Note

Use delete requests with caution as some back ends might reject the delete operation on singletons. According to the OData Specification, singleton entities can be deleted if they are nullable. With regard to the SAP Cloud Application Programming Model, a delete request to a singleton is only feasible if the singleton is annotated with @odata.singleton.nullable.


Last update: April 5, 2024