Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

XS Data Services (XSDS) are a JavaScript library for the XS engine to consume SAP HANA artifacts that have been defined using Core Data Services (CDS), the central data modeling concept of HANA.  The XSDS library supports the import of CDS entities and their associations and offers managed and unmanaged manipulation of such instances. With additional features such as transaction handling, lazy navigation, support for custom types and views, and incremental query building XSDS offers a level of convenience that makes writing native HANA applications with XS a breeze.

What are XS Data Services?

Core Data Services (CDS) are a cross-platform solution to define semantically rich data models for SAP HANA applications.  In essence, a CDS model defines an application’s relevant set of business entities and their relations while abstracting from the underlying technical storage.

The XS Data Services (XSDS) client library for the XS Engine allows JavaScript applications to consume these CDS artifacts as native JavaScript objects.  Instead of writing low-level SQL queries involving database tables and columns, application developers can use XSDS to reason meaningfully about high-level business entities and their relations.  XSDS understands the CDS metadata model offers methods for typical instance management operations.  Advanced queries are constructed using a fluent query API that follows the CDS Query Language specification as closely as possible.

This mini-series of posts expands upon the introductory coverage of Thomas Jung’s blog article on XSDS for SPS9.  Our articles cover the import of CDS entities into native HANA applications, working with managed entity instances in XS JavaScript, and advanced unmanaged queries that will unlock all of HANAs capabilities inside native JavaScript.  XSDS comes pre-installed with SAP HANA SPS9 or later, so you don’t have to install or import anything at all.

Importing CDS Entities

Let’s assume that we’re building a bulletin board application that allows users to post short text messages and to reply to other users’ posts.  Our CDS data model thus defines two entities, user and post:

namespace sap.hana.democontent.xsds;

context bboard {

    entity user {

        key uid: Integer not null;

        Name: String(63) not null;

        Email: String(63);

        Created: UTCDateTime;

    };

    type text {

        Text: String(255);

        Lang: String(2);

    };

    entity post {

        key pid: Integer not null;

        Title: String(63) not null;

        Text: text;

        Author: association [1] to user;

        Parent: association [0..1] to post;

        Rating: Integer;

        Created: UTCDateTime;

    };

};

To use the User and Post entities in our JavaScript application we first have to import them:

$.import("sap.hana.xs.libs.dbutils", "xsds");

var xsds = $.sap.hana.xs.libs.dbutils.xsds;

var Post = XSDS.$importEntity("sap.hana.democontent.xsds", "bboard.post");

var User = XSDS.$importEntity("sap.hana.democontent.xsds", "bboard.user");

The first two lines import the XSDS library itself, and the last two lines define the User and Post entities, respectively.  $importEntity returns a constructor function that is used as a handle for retrieving and creating entity instances.  For most data models this is all that is required to define an entity.

Advanced options allow you to override certain properties of the columns to import.  In the simplest case, you could rename a table column to be used as object property or override the primary key definitions:

var Post = XSDS.$importEntity("sap.hana.democontent.xsds", "bboard.post", {

    UserID: { $column: "uid" },

    Name: { $key: true }

});

You may also provide an existing HDB sequence to generate keys automatically for you.  By using a sequence you will not have to populate the key column for newly created instances yourself.

var User = XSDS.$importEntity("sap.hana.democontent.xsds", "bboard.user", {

    uid: { $key: "\"SAP_HANA_DEMO\".\"sap.hana.democontent.xsds::bb_keyid\"" }

}); 

Note that XSDS does not apply any additional logic to key generation.  It is left to the application and the sequence to generate valid, unique keys for your entities.

Associations

One of the key benefits of CDS is the explicit definition of associations between entities.  XSDS will read association information automatically and integrate associations as references into the entity definition.

To introduce one-to-one associations manually, e.g., for legacy models not converted to CDS yet, you may provide an $association property that specifies the associated entity type and the foreign key that links your parent entity to the associated entity:

var Post = XSDS.$importEntity("sap.hana.democontent.xsds", "bboard.post", {

    Parent: {

        $association: {

            $entity: "sap.hana.democontent.xsds::bboard.post",

        },

        pid: {

            $column: "Reference",

            $none: 0

        }

    }

});

The entity provided by $entity may be the name of the entity of the actual entity constructor itself.  Entities referenced by name are loaded automatically with default options if no matching $importEntity()call can be found.

If the association is a one-to-zero-or-one association, the foreign key should define a specific “no association” value with the $none property.  The $none values will be used to populate the table columns if the parent entity is persisted without associated entity.  In the example above, a value of 0 in the Reference column indicates that the post is not in response to another post.

Note that the “no association” value is different from NULL!  A value of $none indicates no association, whereas a value of NULL indicates that the status of the association is unknown.  If no $none value is specified, however, XSDS will assume that $none: undefined in order to be consistent with the current de-facto behavior of CDS.

One-to-Many Associations

CDS defines one-to-many associations by using backlinks from the targets to the source.  Assume for our example that each post may have any number of unique comments, where each comment contains a reference to its parent post:

entity comment {

    key cid: Integer not null;

    Text: text;

    Author: association [1] to user;

    Parent: association [1] to post; // as backlink

    Created: UTCDateTime;

};

Since HANA SPS9 does not support the creation of CDS backlinks yet we will have to add the backlink definition manually to our import of post:

var Post = XSDS.$importEntity("sap.hana.democontent.xsds", "bboard.post", {

    Comments: {

        $association: {

            $entity: "sap.hana.democontent.xsds::bboard.comment",

            $viaBacklink: "Parent"

        }

    }

});

This is equivalent to importing the following, still unsupported CDS definition:

entity post {

    key pid: Integer not null;

    …

    Comments: association [0..*] to comment via backlink Parent;

};

Comments will appear as a native read-only array-like JavaScript object in our instances of the Post entity:

var post = Post.$get({ pid: 69 });

for (var i = 0; i < post.Comments.length; ++i) {

    if (post.Comments[i].Author.Name === "Alice") { … }

}

We’ll see how to work with these array-like objects further down below.

Many-to-Many Associations

CDS defines many-to-many associations by using linking entities that connect source and target instances.  Assume for our example that any number of tags may be attached to our posts:

entity tag {

    key tid: Integer not null;

    Name: String(63);

};

The actual linkage data is stored in a separate table that corresponds to a (potentially keyless) entity:

@nokey entity tags_by_post {

    lid: Integer;

    Tag: association to tag;

    Post: association to post;

};

Again, as HANA SPS9 does not support linking entities, we will have to enrich our Post data model in our import manually:

var Post = XSDS.$importEntity("sap.hana.democontent.xsds", "bboard.post", {

    Tags: {

        $association: {

            $entity: "sap.hana.democontent.xsds::bboard.tag",

            $viaEntity: "sap.hana.democontent.xsds::bboard.tags_by_post",

            $source: "post",

            $target: "tag",

        }

    }

});

The $source and $target properties indicate the direction of the association.  This import statement is equivalent to importing the following unsupported CDS definition:

entity post {

    key pid: Integer not null;

    …

    Tags: association [0..*] to ds_comments via entity tags_by_post;

};

The tags will appear as a native JavaScript array in our instances of the Post entity:

var post = Post.$get({ pid: 69 });

var tag = Tag.$find({ Text: "cool" });

if (post.Tags.indexOf(tag) < 0) {

 

}

While the representation of tags is similar to that of our comments before, their semantics are quite different.  In particular, attaching a new tag to a post would not remove it from other posts this tag may be attached to.

Unmanaged Associations

The most general form of associations supported by CDS are unmanaged associations that define an arbitrary JOINON condition:

var PostWithTopReplies = XSDS.$importEntity("sap.hana.democontent.xsds", "bboard.post", {

    TopReplies: {

        $association: {

            $entity: "sap.hana.democontent.xsds::bboard.post",

            $on: "$SOURCE.\"TopReplies\".\"Parent\".\"pid\" = $SOURCE.\"pid\" AND " +
                 "$SOURCE.\"TopReplies\".\"Rating\" >= 3"

        }

    }

});

Make sure to quote all field names in the $on expression.  The syntax of the $on condition is preliminary and likely to change for the next release.

Associated instances are included in a read-only array-like object. Due to the unmanaged nature of these associations the contents of the array cannot reflect unsaved changes to the relation and must be refreshed manually.

XSDS Beyond CDS

The XSDS library imports existing CDS entities, but it can also transform entity definitions and derive new entities.  If we want to add a new association not included in the CDS data model, we can derive a new entity in XSDS:

var PostWithComments = Post.$deriveEntity({

    Comments: {

        $association: {

            $entity: "sap.hana.democontent.xsds::bboard.user",

            $viaBacklink: "Post"

        }

    }

});

This extensibility also allows us to work with legacy SQL data models, where we enrich the data model to make implicit associations explicit:

var SqlPost = XSDS.$defineEntity("SqlPost", "\"SOME_TABLE\"", {

    Author: {

        $association: { $entity: User },

        uid: { $column: "Author" }

    }

});

Note that we’re using $defineEntity instead of $importEntity here -- $defineEntity is another method for defining entities in your application that is specialized on creating data models for plain SQL-based tables without CDS metadata.  XSDS will import every table column as an entity property, but as plain SQL lacks the metadata about associations, we need to supply this information ourselves.

Outlook

With our entity imports in place we can now use the constructor functions to work with individual instances or to build advanced queries. Stay tuned for the next installment of our XSDS mini-series!

11 Comments