Skip to Content

SAP HANA SPS 09: New Developer Features; New XSODATA Features

This blog is part of the larger series on all new developer features in SAP HANA SPS 09:

In this blog we will look at new features in the XSODATA service framework in SAP HANA SPS 09.

Configurable Cache-settings for the $metadata request

When calling OData services, the $metadata document is often requested over and over again.  Yet changes to the underlying entity definitions is relatively rare. Therefore in SPS 09 we enable the option to configure caching of these $metadata documents in order to avoid the many redundant queries to the process the metadata.

service {
settings {
  content cache-control "no-store";
  metadata cache-control "max-age=3600,must-revalidate";

ETag Support

The OData specification uses ETags for optimistic concurrency control.  You can read more about the specification here:

If the developer wants to support this feature in XSODATA, they have to enable it per entity in the .xsodata file. Example:

{ entity "sap.test.odata.db.views::Etag" as "EtagAll"
    key ("KEY_00") concurrencytoken;
  entity "sap.test.odata.db.views::Etag" as "EtagNvarchar"
   key ("KEY_00") concurrencytoken ("NVARCHAR_01","INTEGER_03");

If only “concurrencytoken” is specified, all properties, except the key properties, are used to calculate the etag value. If only specific properties are given, only those are used for the calculation. concurrencytoken” cannot be used on aggregated properties with aggregation method AVG (average).

Nullable Properties

All entity properties are automatically generated by the XSODATA layer during create and since they are not nullable, the consumer is now forced to pass dummy values into these property.

However OData supports $filter and $orderby conditions on the “null” value. This means, that it is now possible to treat “null” as a value, if the developer enables it. This behavior can only be enabled for the whole service, not per entity. Example:

service {
settings {
 support null;

Only if this support is enabled, $filter requests like $filter=NVARCHAR_01 eq null are possible. Otherwise “null” is rejected with an exception.

If the support is not enabled, the default behavior applies and all null values are neglected in comparisons and the respective rows are removed from the result (i.e. common database behavior).

Odata Execution Tracking Utility

In order to ease the supportability and analysis of performance for OData request in HANA, we’ve added functionality to request to profile the performance of request processing (executed queries and the time spend in different OData components) in read and write requests. The requested profiling info is then accessible only if the XS engine is in debug mode.

Main usage is – tracking performance by:
1. Add query parameter named ‘profile’ to OData request that notifies the server to produce the report
2. If the parameter is present and engine is in debug mode – OData profiling is done
3. OData response is skipped and the server returns:
     HTML page with the collected information in case profile=html (default)
     JSON response with the collected info in case profile=


OData Explorer

The SAP River Application Explorer has been rebuilt as a general SAP OData Explorer in SPS 09. It allows for the general testing and data generation of XSODATA based services. You can view all records in a service or create/delete/edit individual records. It also supports mass generation of multiple records at once with random value generation. It can be launched from the Web-based Development Workbench (via context menu option on XSODATA service) or directly via the url=

/sap/hana/ide/editor/plugin/testtools/odataexplorer/index.html?appName=<xsodata service path>


You must be Logged on to comment or reply to a post.
  • Hi,
    useful post.

    But i have a problem.
    I'm trying to create a sample application like this:


    The Odata service (appone.xsodata) works fine but when add 'Etags' in the Service (like your code) i have this error into HANA STUDIO:


    Can you help me?

    • Try activating anyway. It should still activate just fine.  This is just the client side check in the Studio not getting updated for the new syntax.

      • I Activated Anyway it and I had following error:

        Keys cannot be specified for source "" as it is a table object.

        What does it mean? Can I use etag with table object or only for view object?

  • Hi Thomas,

    I have the following issue. I created some ODATA services in HANA(SPS09) and I want to consume them in C#.

    For the simple operations (insert, update, delete) it's ok. But for batch-requests it's a problem.

    In HANA a change-set from a batch request should look like:

    Content-Type: application/http
    Content-Transfer-Encoding: binary

    POST http://***/OdataTestsProject/OdataTestService1.xsodata/t_ztable1 HTTP/1.1
    Content-ID: 1
    Content-Type: application/json;odata=verbose;charset=utf-8
    Accept: application/json;odata=verbose
    Content-Length: XXX

    {ID":38,"VERS_ID":14,"COL11":"Col 123","COL12":"Col 12345"}

    The header "Content-Lenght" for an operation is needed.

    If I don't use it, then an error is raised.

    The C# libraries do not includ this "Content-Lenght" header for an operation. It seams that this is an optional header. I checked Microsoft OData service examples for protocols V1-3 and they all accept changesets without content length.

    Please tell me if it's possible to create batch requests without using this header (content-length) for operations.

    Thank you for your support!

    KInd Regards,


    • Its not clear from the OData documentation if content-length is required or not:

      It doesn't explicitly state that it is required but is shown in all examples. I think there might be a case to be made that the underlying Multipart MIME v1.0 used in Batch operations is what specifies that the content-length must be used.

      If you feel that SAP is incorrect in requiring this header, then you should consider entering a support ticket.

      • Hi Thomas,

        I'm a colleague of Iuila and we really appreciate your your answer!

        You're right the documentation is not clear about if the Content-Length is mandatory or optional. However, if you look into the specification(s) it become quite clear:

        "The only exception is that the Content-Length request header is not mandatory in  requests that include request payloads."
        (Open Data Protocol (OData) Specification 2.0 - Page 233 -[MS-ODATA].pdf)

        "As specified in [RFC7230], a request or response SHOULD include a Content-Length header when the message's length can be determined prior to being transferred. OData does not add any additional requirements over HTTP for writing Content-Length."

        (OData Version 4.0 Part 1: Protocol Plus Errata 02 - OData Version 4.0 Part 1: Protocol Plus Errata 02)

        As Iulia pointed out, our client is not setting the Content-Length header and adapting it is not that easy unfortunately. In any case, we don't think the service should raise an error if an optional field is missing in the (batch) request. We'll create a support ticket for this.

        Thanks again for your answer!


  • Hi Thomas,

    in the first section you say it is possible to enable caching for the $metadata requests. Can you pls explain how to obtain that. Similar to static content via .xsaccess file?

    Thanks and best regards,


    • I need to check with the developer of this new feature. I just tried the syntax which was documented for this feature and it didn't work in my system. It produces an activation error. Let me get the correct syntax and get back to you.

      • Actually my bad.  The syntax does work, its just that the editor doesn't understand it and still produces an error.  The error can be ignored as the server side activation works just fine.  You need to add the settings syntax after all your entity definitions.  Here is an example:

        service {



        settings {

          metadata cache-control "no-store";

          content cache-control "max-age=3600,must-revalidate";


        You use normal browser cache control headers. Whatever headers you add in the settings section will be added to the responses.

        • Hi Thomas,

          great, thanks much for your quick response. I'll test this asap.

          One additional question: We usually have several exposed objects in our .xsodata service. Is it possible to set caching for each of these individually?

          Thanks again,


        • Hi Thomas,

          why do you set the cache-control for metadata to "no-store" and the content cache-control to "max-age=3600,must-revalidate"? I would expect to set it vice versa, as the metadata definition changes relatively rare and the content changes very often.



          • That was just an example I cut and pasted out of a real service. For this particular service I guess we wanted to cache the result set but not the metadata. I can see that being reasonable. The metadata might not change often; but when it doesn't its critical to pick up that change for this particular application. On the other hand, the content might change but for this application its fine to cache the results. The point being that the settings give you the ability to control either independently depending upon your applications' requirements.

          • Hi Thomas,

            is it also possible to send an ETAG with the metadata response, which is send back to the server during metadata request, so that the server could send a 304 message, if the metadata was not changed?



          • We do support eTags for concurrency control on the entities themselves; but not on metadata.  I do know that one of the improvements we are looking for the future is to reduce the number of metadata requests. This could end up being one of the ways we do that.

  • Hi Thomas,

    Thank you for your great post!

    I'm working on prototyping project with Fiori on HANA via XS-OData.
    I faced a performance issue. HANA itself is fast but performance becomes slow
    when XS-OData is used. I'd like to identify the reason from XS-OData specification.

    I think "Odata Execution Tracking Utility" may provide us with some hints.
    Could you tell me how to activate debug mode in XS engine and sample of OData request?
    Also, I appreciate it if you share how to analyze "OData Execution Profiler result".

    Kind regards,

    • >Could you tell me how to activate debug mode in XS engine and sample of OData request?

      xsengine.ini -> httpserver -> developer_mode = true

      >Also, I appreciate it if you share how to analyze "OData Execution Profiler result".

      Add profile=html as a URL parameter on your OData request exactly as shown in the screen shot in the above blog.

      • Hi Thomas,

        Thank you for quick reply!

        I checked the pass you described but I couldn't found the parameter "developer_mode"...

        Are there any prerequisite to enable the parameter to be shown?

        screen shot.PNG


        screen shot.PNG
    • Hi Masatoshi,

      we face performance issues with XS OData as well. When using $expand (check this by adding &profile to your url, as Thomas Jung just wrote), the odata implementation creates a local temporary table in hana. The subsequent insert statement on this temporary table seems to be very slow.

      We haven't dived deeper into this, yet.

      If you use $expand as well, this might be the reason for the bad performance.



  • Hi Friends,

    Has any body tried $metadata cache in xsodata. We are building an application in iOS, we are running a CRUD operation on a custom z table from xsjs.

    when I enable metadata caching in xsodata file like

    settings { 

    metadata cache-control "no-store"; 

    content cache-control "max-age=3600,must-revalidate";  }

    An INSERT is happening into Z table but the control is not getting the latest inserted record from SAP HANA. We are using business suite on HANA SPS09.

    When I remove cache and try, it works perfectly file. Is there any other tweaking required like setting max-age or so?

    Thanks in Advance.

    Best Regards,


    • Hi Srini,

      with the seetings you just posted, the content will be cached, but not the metadata. I think you might want it vice versa.

      For us metadata caching worked perfectly.

      Kind regards,

      • Hi Timo,

        I corrected the settings as follows.

        settings {

        support null;

        metadata cache-control "max-age=904800,must-revalidate";

        content cache-control "no-store"; }

        As per my understanding the SAPUI5 control shouldn't fire metadata call, even if it fires there should be a faster response. But I couldn't notice any difference in response time with metadata cache and without settings lines in my xsodata file. Please see screenshot of response with metadata.

        I appreciate your help on this.

        Screenshot_1.pngcache enabled.

        • Hi Srini,

          you have to unflag "Disable cache" in debugging mode of chrome (second line of your screenshot) and reload. Then chrome gives you information on cached content (by saying "(from cache)" in the size/content column.

          Best regards,


          • Hi Timo,

            Thank you so much for your time & efforts in analyzing this issue.

            I tried with removing disable cache in chrome developer tools general settings. It takes the same time with and without cache settings. I'm I doing something wrong here.

            metadata caching is important for me as we have around 40 to 60 services in one xsodata file. Please see screenshot.


          • Be careful.  Google Chrome ignores the Cache-Control or Expires header if you make a request immediately after another request to the same URI in the same tab (by clicking the refresh button or pressing the F5 key).

            Does Chrome reloadButton ignores the cache? - Super User

            I got tricked by the same when testing just now. As soon as I moved the URL to a new tab and loaded from there it got the $metadata from the Cache.

          • Thank you Thomas for the reply. Here is my observations. We are using AJAX calls from UI application.

            1. Tested a service without $metadata cache (chrome normal and incognito mode)

            Chrome is firing $metadata call for every refresh

            2. Tested a service with [metadata cache-control "max-age=900000,must-revalidate";]

            Chrome is not firing calls for every refresh, I fired 5 times but I see 1 call in the network tab.

            Your observation on new window is right and the service metadata is being loaded from Cache.


  • Hi Thomas,

    I seem to be unable to use the OData explorer in my SPS9 system.  Whether I use the preloaded services or one of my own I get:ssodataerr1.JPG

    and yet the direct call to the service works:




    • Are you opening the OData Explorer from the Web Based Development Workbench (right mouse click on the service and choose Open OData Explorer)?  If so the correct service URL should be added to the OData Explorer URL for you.  From your screen shot it seems like the leading forward slash is missing from the service URL.  Have a look at this screen shot from my system for the correct URL format.  Try that and see if it helps.


  • Hi Thomas,

    I successfully created xsodata service and able to test the service in browser with various parameters. And all works fine.

    Need of my application is to GET data using the generated local id for example –

    My result set is –

    {"__metadata": {"type":"odata.CV_ProjectDetailType"

    And I want to access the same result set using –

    GET /odata/odata.xsodata/CV_ProjectDetail(‘543859892167869371’)

    Is there there a way to achieve this ? I got “RESOURCE NOT FOUND” error when I use generated IDs