Introduction

During my studies of SAPUI5 with OData I got stuck with the operations in the model and data binding. So now after successfully integrate all the persistence operations I hope my experience can help somebody with the same problems.

This app is also in my HCP trial, to deploy in HCP you just need to change the persistence.xml in the persistence package.

In this sample app I will try to explain how to build an End to End application with all the basic persistence operations: Create, Read, Update and Delete.

To build this app I am using the following layers:

  1. Persistence: JPA, mysql (local deploy), Hana (HCP);
  2. Service: OData through Apache Olingo;
  3. UI: SAPUI5 with XML views;

All the sources are available in  crudsapui5odatajpa/flight at master · allanfelipesilva/crudsapui5odatajpa · GitHub

UPDATE, version 2:

The POM.xml of persistence and the persistence.xml file are ready to build HCP running application. These files are updated in git.

To build the application you must install Apache Maven. See the tutorial Maven in 5 Minutes.

To download the source you must clone the repository. To install git see Git – Getting Started.

To clone the application just run in the command of your OS:  git clone https://github.com/allanfelipesilva/crudsapui5odatajpa.git

After git finish the download of the code you must build it with Apache Maven. Just run the following command in the folder “flight”:

mvn clean install

Done, all the modules will be ready and the .war will be generated:

Captura de tela de 2015-04-07 21_30_54.png

The .war file will be ready in the folder flight\flight-web\target, you must upload it to HCP trial instance:

Captura de tela de 2015-04-07 21_32_17.png

If you want to change the source code, you must create the eclipse projects in each of the app folders, go in the command line and execute the following command to create the eclipse projects:

mvn eclipse:eclipse

There will be three different projects in your eclipse one for each layer:

To import the projects in eclipse , just go to menu Import -> More -> Existing project in workspace

/wp-content/uploads/2015/04/eclipse_678163.png

Persistence

The persistence layer consists of a JPA class with three properties:

  • Id: integer auto generate
  • Departure: String
  • Destination: String

Source code:

Class.png

After the creation of the class you must parametrize the persistence.xml accordingly to your setup.

You must create a schema in your database and update the URL.

Dont forget to update the user and password:

/wp-content/uploads/2015/04/persistence_678165.png

If you are using a different database driver, dont forget to update the POM.xml with your driver.

To check the persistence layer, use the tool provided by your database, in mysql command line:

/wp-content/uploads/2015/04/mysql_678166.png

Service

The service layer consists of the Apache Olingo implementation, there is one class mapped in the web.xml as a servlet with all the service layer.

The class is in the package flight-service.

/wp-content/uploads/2015/04/odataclass_678167.png

The name in the property PUNIT_NAME must be the same name from your persistence.xml.

The web.xml from the flight-web pacckage must contain the mapping of this class to a servlet:

/wp-content/uploads/2015/04/webxml_678168.png

You can test the service layer though the servlet URL directly in the browser:

To get all the parameters of the persistence layer, use $metadata to check it in the end of the URL.

/wp-content/uploads/2015/04/odatametadata_678169.png

Now lets test all the operation with our service layer.

For some of the tests,  a REST client is necessary, such as “POSTMAN” or “Advanced Rest Client App” from chrome web store.

Read an Entity:

To list the flights in the database, just request the list of the entity:

/wp-content/uploads/2015/04/odatalist_678170.png

Create an Entry

Send a POST with ID 0, the ID will be generated automatically.

postmanAddEntry.png

Update an Entry

Send a PUT in the recently created entry:

updateEntry.png

Delete an Entry

Send a DELETE method to the URL of the entry to be deleted.

deleteEntry.png

View

If the service layer is OK, all the operations can be triggered from SAPUI5.

The application consists of two pages, one for the list of Flights and another one to the Add, Delete, Update operations.

The index is below:

/wp-content/uploads/2015/04/indexhtml_678175.png

List View:

/wp-content/uploads/2015/04/list_678133.png

In the list view we will bind our OData with our sap.m.Table:

The items property must point to the collection name from OData and the row items from the properties from the $metadata:

/wp-content/uploads/2015/04/indexview_678178.png

in the controller you must set the oModel for your view with the list:

sap.ui.controller("flightweb.index", {
     onInit : function(evt) {
          this.getView().addDelegate(
                    {
                         onBeforeShow : function(evt) {
                              var oModel = new sap.ui.model.odata.ODataModel(
                                        "FlightOData.svc/");
                              evt.to.setModel(oModel);
                         }
                    });
     },

     onAdd : function(evt) {
          app.to("addflight");
     },
     onDetailPress : function(event) {
          var bindingContext = event.getSource().getBindingContext();
          var flightid = bindingContext.getProperty("Id");
          var myObject = bindingContext.getObject();
          app.to("addflight", "slide", bindingContext);

     }
});

Add Entry:

To insert a new entry,there is a button in the list,

this button will call the method onAdd in the controller.

the controller method will call the add view:

onAdd : function(evt) {
          app.to("addflight");
     },

/wp-content/uploads/2015/04/add_678174.png

The form must have the binding to the odata properties:

/wp-content/uploads/2015/04/formview_678183.png

The save button will trigger the call of a POST operation in the controller:

For the creation of a new entry, the field ID will be blank, so the “createEntry” method will be called in this snippet:

The creation of a new entry is done by the code in blue:

     handleSavePress : function(evt) {

          var oModel = this.getView().getModel();          

          var vProperties = {};          

          vProperties.Id = this.getView().byId("id").getValue();          

          vProperties.Departure = this.getView().byId("departure").getValue();          

          vProperties.Destination = this.getView().byId("destination").getValue();

          if (vProperties.Id == "") {   

               vProperties.Id = 0;

               oModel.createEntry("Flights", vProperties);

          } else {   

               var oEntry = {};  

               var mParameters = {};   

               mParameters.context = this.getView().getBindingContext();   

               mParameters.success = this._fnSuccess;   

               mParameters.error = this._fnError;   

               oEntry.Departure = vProperties.Departure;   

               oEntry.Destination = vProperties.Destination;   

               oModel.update("", oEntry, mParameters);

          }

          oModel.submitChanges(this._fnSuccess, this._fnError);         

          oModel.refresh();

},

Change Entry:

To change an entry, the method update should be triggered in the model.

in the screen the button “Save” will call the update function.

/wp-content/uploads/2015/04/create_678161.png

The hidden field ID in the screen will be populated with the ID of the flight, so the following code in blue will be executed:

     handleSavePress : function(evt) {

          var oModel = this.getView().getModel();          

          var vProperties = {};          

          vProperties.Id = this.getView().byId("id").getValue();          

          vProperties.Departure = this.getView().byId("departure").getValue();          

          vProperties.Destination = this.getView().byId("destination").getValue();

          if (vProperties.Id == "") {   

               vProperties.Id = 0;

               oModel.createEntry("Flights", vProperties);

          } else {   

               var oEntry = {};            

               var mParameters = {};             

               mParameters.context = this.getView().getBindingContext();             

               mParameters.success = this._fnSuccess;             

               mParameters.error = this._fnError;             

               oEntry.Departure = vProperties.Departure;             

               oEntry.Destination = vProperties.Destination;             

               oModel.update("", oEntry, mParameters);       

          }

          oModel.submitChanges(this._fnSuccess, this._fnError);

          oModel.refresh();

},

Delete an Entity:

To delete an entity, the controller will call the remove method in the model.

the following code snippet is reponsible for that:

handleDeletePress : function() {
                              var oModel = this.getView().getModel();
                              var flightid = this.getView().byId("id").getValue();
                              oModel.remove("/Flights(" + flightid + "L)");
                              oModel.refresh();
                              app.back();

                         },

Conclusion

I really hope this sample can help somebody with problems in the binding and call of model operations.

If you find any bug, or want to add more functionality please contact me so I can provide access to github.

If this somehow helped you, please like it and share

To report this post you need to login first.

13 Comments

You must be Logged on to comment or reply to a post.

  1. Robin van het Hof

    Nice, extensive blog!

     

    This will certainly help others using JPA/Apache Olingo doing OData CRUD from a Java platform (I would’ve chosen SAP HANA Cloud Platform, but alas )

    (0) 
  2. Hans-Joerg Alles

    Hello Allan, your example helped me a lot preparing prototypes for our developers using SAPUI5 against SAP and NON-SAP-Systems !

    But as always in our business we have to dive into Details, which produce some more problems ( where i am just in ).

    I can successfully CRUD with one or more tables ( Technic: SAPUI5, Apache Olingo, MariaDB ) as long as there are no foreign key constraints. (employee-table with department-id referencing id in department-table). I think there is something wrong how the Eclipse is generating JPA Entities from table. All the service-URLS are working(metadata, entitysets, expands) but when i try to insert an employee putting a value to the department-id i am getting a JPA-Error (…field could not be null )..the entity name is right adressed.  I would like to share my coding ( where would be the place in context of your article? ) or maybe you have a working example of CRUD with foreign key thematic ?

    Thanks a lot

    Hans-Jörg

    (0) 
    1. Allan Silva Post author

      Hi Hans, thanks a lot for the feedback.

      Can you post the json package that your sapui5 is trying to send ?

      I have an example with foreign key with olingo, deep inserts are not working on olingo yet.

      To make sure OLingo and JPA are working together please consider to test it before on Postman or Rest Client on Chrome.

       

      In this scenario I am creating an entry for RFID entity and in the field truckdetails I am given the URL to the truck linked to this RFID.

      The package I am sending to olingo:

      header fields:
      
      Content-Type: application/json
      
      method: POST
      message body:
      
      {
        "Id":0,
        "Rfid":" 13 1C E2 C23",
        "J_1BNFTRUCKDetails": {
         "__metadata": {
              "uri": "J_1BNFTRUCKs(1)"
            }
        },
      
      }
      

      I believe foreign keys handling are very welcome in this post,  I can link to your post or you can write a new section in this page.

       

      Anyway, would be a good idea to have it in the same app,  I can share the commit authorization to your user.

      (0) 
      1. Hans-Joerg Alles

        Hello Allan,

         

        let me quick try another way which i am right in now. I will give you the necessary Information tomorrow morning. I am still believing there is something wrong how Apache Olingo is working together with the generated entity classes in Eclipse JPA Tools.

        Thanks a lot and until tomorrow

        Hans-Jörg

        (0) 
        1. Allan Silva Post author

          Hi Hans, in my project with foreign keys I am using this dependency:

           

          <dependency>

             <groupId>org.eclipse.persistence</groupId>

             <artifactId>javax.persistence</artifactId>

             <version>2.1.0</version>

            </dependency>

          (0) 
          1. Hans-Joerg Alles

            Hello Allan,

            i am using two Eclipse projects:

            A for delivering the OData Service via Apache Olingo JPA against MariaDB tables.

            B for consuming the Service and rendering the datas via SAPUI5 in the frontend.

            I am not using Maven so far so i will send you:

            persistence.xml from A

            metadata from A

            examples of entitysets from A

            the sapui5 dialog (in the background you see the datas)

             

            I try to insert an employee in the emp-table (there is a foreign key on field deptid which references to the field id in dept-table. And i think there is the mistake coming out of the generated entity classes ( in the gets of the Service i see the field department which is only the join. I am getting a JPA create error because of deptid could not be null. But how do i put a value in that field ? I will continue tomorrow…but anyways thanks a lot for your help and hopefully the screenshots are not to much for you .

            Hans/wp-content/uploads/2015/04/persistence_690337.jpg

            Emps.jpg

            Depts.jpg

            Depts_Emp.jpg

            sapui5View.jpg/wp-content/uploads/2015/04/metamodel_690377.jpg

            (0) 
          2. Hans-Joerg Alles

            Good morning Allan,

             

            i send you the Create-payload, the error message and the JPA entities from Emp and Dept table.

            I am focusing on the field deptid which i don’t see in the Service and which is ‘hided’ behind the reference department. If i change the create command to field deptid then i get bad request error.

            Thank you

            HansRequestPayload.jpgODataJPAError.jpgJPAError.jpgManyToOneinEmp.jpgOneToManyDept.jpg

            (0) 
            1. Allan Silva Post author

              Hello Hans,

              The problem is only when you send the request through SAPUI5 ? if you try to send it through postman or any other REST, it works ?

               

              Your property name is “DeptDetails” and not “departament” and the value should not be an int “3”, it should be “Depts(3)”.

               

              And a link should be used in the payload, the payload should look like:

               

              ..<a:name/>

              <a:author/><d:link type="application/atom+xml;type=Dept" title="DeptDetails" href="Depts(3)"/><a:content type...

               

               

              The other possible solution is to use the URL of binding /Depts(3)/EmpDetails. and execute the post in this context.  – I dont know if olingo supports that.

               

              Anyway, I will try to post my example of Master/Detail as soon as possible with the association operations as soon as possible.

              (0) 
              1. Hans-Joerg Alles

                Hi Allan, i will try this out as soon as possible !

                I also went to a cleanup of my entities:

                For MySQL/MariaDB when using an autoincrement index (id) in your tables you have to use the @GeneratedValue Annotation. If not the SQL insert command tries to insert the ID field.

                I will change and test code now.

                Thank you./wp-content/uploads/2015/04/mariadb_691240.jpg

                (0) 
              2. Hans-Joerg Alles

                Hi Allan,

                 

                First test->Bad Request->it doesn’t reach the database…so maybe the property name is department (with this name i reach the database).

                Error1.jpg

                (0) 
                1. André Bezerra

                  Hello,

                   

                  were you able to solve this problem?
                  I have a similar case. I have one Entity called “Employee” that connects to “Rating” Entity.
                  I cannot seem to perform any POST/PUT because the OData Processor is unable to fill the rating attribute (either with the unique identifier or with the Link reference).

                   

                  Thanks in Advance

                  (0) 
  3. Alan Gong

    Hi Allan,

     

        Thanks for your sharing!

        For the delete method, can we use the composite key to delete the entry?

     

    Thanks in advance

    Alan

    (0) 

Leave a Reply