Search

    Advanced Concepts

    Find here an overview of advanced concepts.

    Content

    The CDS Data Store

    The Data Store API is used to execute CQN statements against the underlying data store (typically a database). It’s a technical component that allows to execute CDS QL statements. The CDS Data Store is used to implement the Persistence Service, but is also available independent from the CAP Java SDK. So, it’s not a service and isn’t based on events and event handlers.

    The CdsDataStore API is similar to the CqnService API. The only difference is, that the run method is called execute:

    CdsDataStore dataStore = ...;
    Select query = Select.from("bookshop.Books").where(b -> b.get("ID").eq(17));
    Result result = dataStore.execute(query);
    

    Use the CdsDataStore API to set user session context information. Utilize the SessionContext API which follows a builder pattern, as shown in the following example:

    SessionContext sessionContext = SessionContext.create().setUserContext(UserContext.create().setLocale(Locale.US).build()).build());
    dataStore.setSessionContext(sessionContext);
    

    When implementing a CAP application, using the Persistence Service is preferred over the CDS Data Store.

    Execute Native SQL with Spring’s JDBC Template

    The JDBC template is the Spring API, which in contrast to the CQN APIs allows executing native SQL statements and call stored procedures (alternative to Native HANA Object). It seamlessly integrates with Spring’s transaction and connection management. The following example shows the usage of JdbcTemplate in the custom handler of a Spring Boot enabled application. It demonstrates the execution of the stored procedure and native SQL statement.

    @Autowired
    JdbcTemplate jdbcTemplate;
    ...
    
    public void setStockForBook(int id, int stock) {
       jdbcTemplate.update("call setStockForBook(?,?)", id, stock);  // Run the stored procedure `setStockForBook(id in number, stock in number)`
    }
    
    public int countStock(int id) {
       SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("id", id);
       return jdbcTemplate.queryForObject(
          "SELECT stock FROM Books WHERE id = :id", namedParameters, Integer.class); // Run native SQL
    }
    

    See Class JdbcTemplate for more details.

    Using CDS QL with a Static CDS Model

    The static model and accessor interfaces can be generated using the CDS Maven Plugin.

    ❗ Warning
    Currently, the generator doesn’t support using reserved Java keywords as identifiers in the CDS model. Conflicting element names can be renamed in Java using the @cds.java.name annotation.

    Static Model in the Query Builder

    The Query Builder API allows you to dynamically create CDS QL queries using entity and element names given as strings:

    Select.from("my.bookshop.Books")
      .columns("title")
      .where(book -> book.to("author").get("name").eq("Edgar Allan Poe"));
    

    This query is constructed dynamically. It’s checked only at runtime that the entity my.bookshop.Authors actually exists and that it has the element name. Moreover, the developer of the query doesn’t get any code completion at design time. These disadvantages are avoided by using a static model to construct the query.

    Model Interfaces

    The static model is a set of interfaces that reflects the structure of the CDS model in Java (like element references with their types, associations, etc.) and allow to fluently build queries in a type-safe way. For every entity in the model, the model contains a corresponding StructuredType interface, which represents this type. As an example, for this CDS model the following model interfaces are generated:

    CDS model

    namespace my.bookshop;
    
    entity Books {
      key ID : Integer;
      title  : String(111);
      author : Association to Authors;
    }
    
    entity Authors {
      key ID : Integer;
      name   : String(111);
      books  : Association to many Books on books.author = $self;
    }
    

    Find this source also in cap/samples.

    Java

    @CdsName("my.bookshop.Books")
    public interface Books_ extends StructuredType<Books_> {
      ElementRef<Integer> ID();
      ElementRef<String> title();
      Authors_ author();
      Authors_ author(Function<Authors_, Predicate> filter);
    }
    
    @CdsName("my.bookshop.Authors")
    public interface Authors_ extends StructuredType<Authors_> {
      ElementRef<Integer> ID();
      ElementRef<String> name();
      Books_ books();
      Books_ books(Function<Books_, Predicate> filter);
    }
    

    Accessor Interfaces

    The corresponding data is captured in a data model similar to JavaBeans. These beans are interfaces generated by the framework and providing the data access methods - getters and setters - and containing the CDS element names as well. The instances of the data model are created by the CDS QL Execution Engine (see the following example).

    Note the following naming convention: the model interfaces, which represent the structure of the CDS Model, always end with underscore, for example Books_. The accessor interface, which refers to data model, is simply the name of the CDS entity - Books.

    The following data model interface is generated for Books:

    @CdsName("my.bookshop.Books")
    public interface Books extends CdsData {
    
      String ID = "ID";
      String TITLE = "title";
      String AUTHOR = "author";
    
      Integer getID();
      void setID(Integer id);
    
      String getTitle();
      void setTitle(String title);
    
      Authors getAuthor();
      void setAuthor(Map<String, ?> author);
    }
    

    Javadoc comments

    The static model and accessor interfaces can be extended with Javadoc comments.

    Currently the generator supports Javadoc comments using the interface and getter/setter methods. The following example shows Javadoc comments defined in the CDS model and how they appear in the generated interfaces.

    namespace my.bookshop;
    /**
     * The creator/writer of a book, article, or document.
     */
    entity Author {
    	   key Id : Integer;
    	   /**
    	    * The name of the author.
    	    */
    	   name : String(30);
    }
    
    /**
     * The creator/writer of a book, article, or document.
     */
    @CdsName("my.bookshop.Author")
    public interface Author extends CdsData {
    
      String ID = "Id";
      String NAME = "name";
    
      Integer getId();
      void setId(Integer id);
      /**
       * The name of the author.
       */
      String getName();
      /**
       * The name of the author.
       */
      void setName(String name);
    }
    

    Usage

    In the query builder, the interfaces reference entities. The interface methods can be used in lambda expressions to reference elements or to compose path expressions:

    Select<Books_> query = Select.from(Books_.class)			// Note the usage of model interface Books_ here
      .columns(book -> book.title())
      .where  (book -> book.author().name().eq("Edgar Allan Poe"));
    
    List<Books> books = dataStore.execute(query).listOf(Books.class);	// After executing the query the result can be converted to a typed representation List of Books.
    
    Show/Hide Beta Features