Skip to Content
Technical Articles
Author's profile photo Manuel Stampp

Convert Mobile Business Object package to OData Service

Did you know that it can be quite easy to convert Mobile Business Object (MBO) packages (running on SAP Mobile Platform 3.0, MBO Runtime) into an OData service (with Cache Database) that will reuse the same download logic and can keep the same data integration (for RFC, HTTP or JDBC)?

SAP Mobile Services, Mobile Back-End Tools (MBT) offer a feature that is capable of converting an MBO package into OData CSDL and give you the possibilities to run in SAP Business Technology Platform (BTP) or on Premise.

This blog post shall give an introduction about how such a conversion can be executed. It is complementary to and requires knowledge taught in the following tutorials:
Create a Simple OData Service with Mobile Back-End Tools and Create a cached OData Service for improved Offline OData

Mobile Backend Tools are supported both in SAP Business Application Studio environment as well as in Visual Studio Code locally via Marketplace extension. Depending on your requirements you should choose the environment.

  • If you plan to run the generated service in SAP BTP
    • SAP Business Application Studio will be better choice for most developers as it allows you to leverage the same environment during design time and run time.
    • The CSDL graphical modeler is only available in SAP Business Application Studio.
    • SAP Business Application Studio as a cloud solution will run out of the box with the preset for SAP Mobile Services and does not require a manual setup of your development environment as well as being OS agnostic
  • If you plan to run the generated service in an on premise architecture
    • You can still connect it via SAP Cloud Connector to SAP Mobile Services, but you might want to generate and develop the service in an on-premise architecture leveraging the Visual Studio Code extension for mobile back-end tools
    • For Visual Studio Code you need to setup your own environment locally

If you migrate an MBO package that used to connect via JDBC to a database which is not SAP HANA, you might want to convert, develop and run your MBT-based service-application on premise in VS Code - as not all database types can be easily and securely exposed to SAP Business Technology Platform via SAP Cloud Connector.

 

When you migrate an MBO, instead of creating a new model and extending it with custom handler annotations (as in the tutorials), you can instead just convert your MBO package and go on with the rest. Nevertheless a bit of understanding about what is actually happening will be helpful to implement optimizations and fix possible errors, so therefore I still recommend going through all these tutorials if you want to migrate an MBO.

Please check out the following steps for a model conversion in SAP Business Application Studio.

  1. Open an empty workspace in SAP Business Application Studio. If your workspace is not empty, perform the
    following steps:

    • From the Terminal menu, select the New Terminal option.
    • After the $ prompt in the Terminal window, enter a mkdir command to create a project folder.
    • Then, from File menu, select Open and select your new folder to open it in your
      workspace explorer.
  2. Copy your MBO package descriptor  deployment-unit.xml to the folder in your workspace. Therefore, extract this file from the MBO application in MBO Toolkit or via package export from SAP Control Center. If you do not have a package and want to try the migration, you can also use the following demo-purpose package:
    Click to expand to obtain a demo purpose AFX file content.
    <!--AFX Document -->
    <package name="MigrationPoC" product-version="3.0.17" version="1.0" check-interval="0" xmlns="http://www.sybase.com/sup/afx">
    <database name="migrationPoC1_0"/>
    <database-class name="MigrationPoCDB"/>
    <class name="BAPI_EPM_BP_CHANGE_HEADERDATA">
    <attribute name="BP_ID" type="string?" max-length="10"/>
    <attribute name="BP_ROLE" type="string?" max-length="3"/>
    <attribute name="EMAIL_ADDRESS" type="string?" max-length="255"/>
    <attribute name="PHONE_NUMBER" type="string?" max-length="30"/>
    <attribute name="FAX_NUMBER" type="string?" max-length="30"/>
    <attribute name="WEB_ADDRESS" type="string?" max-length="255"/>
    <attribute name="COMPANY_NAME" type="string?" max-length="80"/>
    <attribute name="LEGAL_FORM" type="string?" max-length="10"/>
    <attribute name="CURRENCY_CODE" type="string?" max-length="5"/>
    <attribute name="CITY" type="string?" max-length="40"/>
    <attribute name="POSTAL_CODE" type="string?" max-length="10"/>
    <attribute name="STREET" type="string?" max-length="60"/>
    <attribute name="BUILDING" type="string?" max-length="10"/>
    <attribute name="COUNTRY" type="string?" max-length="3"/>
    <attribute name="ADDRESS_TYPE" type="string?" max-length="2"/>
    <attribute name="ADDRESS_VAL_START_DATE" type="decimal?"/>
    <attribute name="ADDRESS_VAL_END_DATE" type="decimal?"/>
    <attribute name="CREATED_BY" type="string?" max-length="10"/>
    <attribute name="CREATED_AT" type="decimal?"/>
    <attribute name="CHANGED_BY" type="string?" max-length="10"/>
    <attribute name="CHANGED_AT" type="decimal?"/>
    </class>
    <class name="BAPI_EPM_BP_CHANGE_HEADERDATAX1">
    <attribute name="EMAIL_ADDRESS" type="string?" max-length="1"/>
    <attribute name="PHONE_NUMBER" type="string?" max-length="1"/>
    <attribute name="FAX_NUMBER" type="string?" max-length="1"/>
    <attribute name="WEB_ADDRESS" type="string?" max-length="1"/>
    <attribute name="BUILDING" type="string?" max-length="1"/>
    <attribute name="COUNTRY" type="string?" max-length="1"/>
    <attribute name="COMPANY_NAME" type="string?" max-length="1"/>
    <attribute name="LEGAL_FORM" type="string?" max-length="1"/>
    </class>
    <class name="BAPI_EPM_BP_CHANGE_BP_ID">
    <attribute name="BP_ID" type="string" max-length="10"/>
    </class>
    <entity name="BusinessPartner" alternate-key="BP_ID,BP_ROLE" key="surrogateKey" partition-by-requestor="false">
    <attribute name="BP_ID" type="string" max-length="10" cdb-column="BP_ID"/>
    <attribute name="BP_ROLE" type="string" max-length="3" cdb-column="BP_ROLE"/>
    <attribute name="EMAIL_ADDRESS" type="string?" max-length="255" cdb-column="EMAIL_ADDRESS"/>
    <attribute name="PHONE_NUMBER" type="string?" max-length="30" cdb-column="PHONE_NUMBER"/>
    <attribute name="FAX_NUMBER" type="string?" max-length="30" cdb-column="FAX_NUMBER"/>
    <attribute name="WEB_ADDRESS" type="string?" max-length="255" cdb-column="WEB_ADDRESS"/>
    <attribute name="COMPANY_NAME" type="string?" max-length="80" cdb-column="COMPANY_NAME"/>
    <attribute name="LEGAL_FORM" type="string?" max-length="10" cdb-column="LEGAL_FORM"/>
    <attribute name="CITY" type="string?" max-length="40" cdb-column="CITY"/>
    <attribute name="POSTAL_CODE" type="string?" max-length="10" cdb-column="POSTAL_CODE"/>
    <attribute name="STREET" type="string?" max-length="60" cdb-column="STREET"/>
    <attribute name="BUILDING" type="string?" max-length="10" cdb-column="BUILDING"/>
    <attribute name="COUNTRY" type="string?" max-length="3" cdb-column="COUNTRY"/>
    <attribute name="surrogateKey" type="long" generated="true"/>
    <permit-access roles="Everyone"/>
    <allow-dynamic-query enable="true"/>
    <publish with-replay="true"/>
    <query name="findAll" type="BusinessPartner*">
    <sql>SELECT x.* FROM BusinessPartner x</sql>
    </query>
    <query name="findByBP_ID" type="BusinessPartner*">
    <parameter name="BP_ID" type="string" max-length="10"/>
    <sql>SELECT x.* FROM BusinessPartner x
    WHERE x.BP_ID = :BP_ID</sql>
    </query>
    <query name="findByBP_ROLE" type="BusinessPartner*">
    <parameter name="BP_ROLE" type="string" max-length="3"/>
    <sql>SELECT x.* FROM BusinessPartner x
    WHERE x.BP_ROLE = :BP_ROLE</sql>
    </query>
    <query name="findByPrimaryKey" type="BusinessPartner">
    <parameter name="BP_ID" type="string" max-length="10"/>
    <parameter name="BP_ROLE" type="string" max-length="3"/>
    <sql>SELECT x.* FROM BusinessPartner x
    WHERE x.BP_ID = :BP_ID
    AND x.BP_ROLE = :BP_ROLE</sql>
    </query>
    <index name="findByPrimaryKeyIndex" attributes="BP_ID,BP_ROLE"/>
    <operation name="update" update="true" cache-effect-policy="apply-operation-results">
    <permit-access roles="Everyone"/>
    <local-var name="HEADERDATA_var" type="BAPI_EPM_BP_CHANGE_HEADERDATA" server-only="true"/>
    <server-code language="java">{
    HEADERDATA_var = null;
    java.lang.String var_text = "{\"BP_ROLE\":null,\"BUILDING\":null,\"ADDRESS_VAL_START_DATE\":null,\"COUNTRY\":null,\"COMPANY_NAME\":null,\"CHANGED_AT\":null,\"FAX_NUMBER\":null,\"STREET\":null,\"BP_ID\":null,\"PHONE_NUMBER\":null,\"CHANGED_BY\":null,\"CREATED_BY\":null,\"CREATED_AT\":null,\"WEB_ADDRESS\":null,\"ADDRESS_TYPE\":null,\"CITY\":null,\"POSTAL_CODE\":null,\"ADDRESS_VAL_END_DATE\":null,\"LEGAL_FORM\":null,\"CURRENCY_CODE\":null,\"EMAIL_ADDRESS\":null}";
    java.lang.Object var_json = com.sybase.afx.json.JsonReader.parse(var_text);
    HEADERDATA_var = MigrationPoC.server.BAPI_EPM_BP_CHANGE_HEADERDATA.fromJSON(var_json);
    if (HEADERDATA_var == null)
    {
    HEADERDATA_var = new MigrationPoC.server.BAPI_EPM_BP_CHANGE_HEADERDATA();
    }
    }</server-code>
    <local-var name="HEADERDATAX_var" type="BAPI_EPM_BP_CHANGE_HEADERDATAX1" server-only="true"/>
    <server-code language="java">{
    HEADERDATAX_var = null;
    java.lang.String var_text = "{\"BUILDING\":null,\"COUNTRY\":null,\"COMPANY_NAME\":null,\"WEB_ADDRESS\":null,\"FAX_NUMBER\":null,\"LEGAL_FORM\":null,\"PHONE_NUMBER\":null,\"EMAIL_ADDRESS\":null}";
    java.lang.Object var_json = com.sybase.afx.json.JsonReader.parse(var_text);
    HEADERDATAX_var = MigrationPoC.server.BAPI_EPM_BP_CHANGE_HEADERDATAX1.fromJSON(var_json);
    if (HEADERDATAX_var == null)
    {
    HEADERDATAX_var = new MigrationPoC.server.BAPI_EPM_BP_CHANGE_HEADERDATAX1();
    }
    }</server-code>
    <local-var name="BP_ID_var" type="BAPI_EPM_BP_CHANGE_BP_ID" server-only="true"/>
    <server-code language="java">{
    BP_ID_var = null;
    java.lang.String var_text = "{\"BP_ID\":\"\"}";
    java.lang.Object var_json = com.sybase.afx.json.JsonReader.parse(var_text);
    BP_ID_var = MigrationPoC.server.BAPI_EPM_BP_CHANGE_BP_ID.fromJSON(var_json);
    if (BP_ID_var == null)
    {
    BP_ID_var = new MigrationPoC.server.BAPI_EPM_BP_CHANGE_BP_ID();
    }
    }</server-code>
    <ds-operation>
    <input-record type="sap:BAPI_EPM_BP_CHANGE_INPUT">
    <bind name="HEADERDATA" type="sap:BAPI_EPM_BP_CHANGE_HEADERDATA">
    <bind name="BP_ID" type="string?" value="BP_ID" alternate-value="HEADERDATA_var.BP_ID"/>
    <bind name="BP_ROLE" type="string?" value="BP_ROLE" alternate-value="HEADERDATA_var.BP_ROLE"/>
    <bind name="EMAIL_ADDRESS" type="string?" value="EMAIL_ADDRESS" alternate-value="HEADERDATA_var.EMAIL_ADDRESS"/>
    <bind name="PHONE_NUMBER" type="string?" value="PHONE_NUMBER" alternate-value="HEADERDATA_var.PHONE_NUMBER"/>
    <bind name="FAX_NUMBER" type="string?" value="FAX_NUMBER" alternate-value="HEADERDATA_var.FAX_NUMBER"/>
    <bind name="WEB_ADDRESS" type="string?" value="WEB_ADDRESS" alternate-value="HEADERDATA_var.WEB_ADDRESS"/>
    <bind name="COMPANY_NAME" type="string?" value="COMPANY_NAME" alternate-value="HEADERDATA_var.COMPANY_NAME"/>
    <bind name="LEGAL_FORM" type="string?" value="LEGAL_FORM" alternate-value="HEADERDATA_var.LEGAL_FORM"/>
    <bind name="CURRENCY_CODE" type="string?" value="CITY" alternate-value="HEADERDATA_var.CURRENCY_CODE"/>
    <bind name="CITY" type="string?" value="POSTAL_CODE" alternate-value="HEADERDATA_var.CITY"/>
    <bind name="POSTAL_CODE" type="string?" value="STREET" alternate-value="HEADERDATA_var.POSTAL_CODE"/>
    <bind name="STREET" type="string?" value="BUILDING" alternate-value="HEADERDATA_var.STREET"/>
    <bind name="BUILDING" type="string?" value="COUNTRY" alternate-value="HEADERDATA_var.BUILDING"/>
    <bind name="COUNTRY" type="string?" value="HEADERDATA_var.COUNTRY"/>
    <bind name="ADDRESS_TYPE" type="string?" value="HEADERDATA_var.ADDRESS_TYPE"/>
    <bind name="ADDRESS_VAL_START_DATE" type="decimal?" value="HEADERDATA_var.ADDRESS_VAL_START_DATE"/>
    <bind name="ADDRESS_VAL_END_DATE" type="decimal?" value="HEADERDATA_var.ADDRESS_VAL_END_DATE"/>
    <bind name="CREATED_BY" type="string?" value="HEADERDATA_var.CREATED_BY"/>
    <bind name="CREATED_AT" type="decimal?" value="HEADERDATA_var.CREATED_AT"/>
    <bind name="CHANGED_BY" type="string?" value="HEADERDATA_var.CHANGED_BY"/>
    <bind name="CHANGED_AT" type="decimal?" value="HEADERDATA_var.CHANGED_AT"/>
    </bind>
    <bind name="HEADERDATAX" type="sap:BAPI_EPM_BP_CHANGE_HEADERDATAX">
    <bind name="EMAIL_ADDRESS" type="string?" default-value="X" value="HEADERDATAX_var.EMAIL_ADDRESS"/>
    <bind name="PHONE_NUMBER" type="string?" default-value="X" value="HEADERDATAX_var.PHONE_NUMBER"/>
    <bind name="FAX_NUMBER" type="string?" default-value="X" value="HEADERDATAX_var.FAX_NUMBER"/>
    <bind name="WEB_ADDRESS" type="string?" default-value="X" value="HEADERDATAX_var.WEB_ADDRESS"/>
    <bind name="BUILDING" type="string?" default-value="X" value="HEADERDATAX_var.BUILDING"/>
    <bind name="COUNTRY" type="string?" default-value="X" value="HEADERDATAX_var.COUNTRY"/>
    <bind name="COMPANY_NAME" type="string?" default-value="X" value="HEADERDATAX_var.COMPANY_NAME"/>
    <bind name="LEGAL_FORM" type="string?" default-value="X" value="HEADERDATAX_var.LEGAL_FORM"/>
    </bind>
    <bind name="BP_ID" type="sap:BAPI_EPM_BP_CHANGE_BP_ID">
    <bind name="BP_ID" type="string?" value="BP_ID" default-value="" alternate-value="BP_ID_var.BP_ID"/>
    </bind>
    </input-record>
    <ds-meta-data xmlns:interaction="http://www.sybase.com/sup/ds/schema/deployment/core/interaction" xmlns:sap="http://www.sybase.com/sup/ds/schema/deployment/sap">
    <sap:dataSource name="ERP_JCO"/>
    <sap:function name="BAPI_EPM_BP_CHANGE">
    <sap:parameter name="HEADERDATA.BP_ID"/>
    <sap:parameter name="HEADERDATA.BP_ROLE"/>
    <sap:parameter name="HEADERDATA.EMAIL_ADDRESS"/>
    <sap:parameter name="HEADERDATA.PHONE_NUMBER"/>
    <sap:parameter name="HEADERDATA.FAX_NUMBER"/>
    <sap:parameter name="HEADERDATA.WEB_ADDRESS"/>
    <sap:parameter name="HEADERDATA.COMPANY_NAME"/>
    <sap:parameter name="HEADERDATA.LEGAL_FORM"/>
    <sap:parameter name="HEADERDATA.CURRENCY_CODE"/>
    <sap:parameter name="HEADERDATA.CITY"/>
    <sap:parameter name="HEADERDATA.POSTAL_CODE"/>
    <sap:parameter name="HEADERDATA.STREET"/>
    <sap:parameter name="HEADERDATA.BUILDING"/>
    <sap:parameter name="HEADERDATA.COUNTRY"/>
    <sap:parameter name="HEADERDATA.ADDRESS_TYPE"/>
    <sap:parameter name="HEADERDATA.ADDRESS_VAL_START_DATE"/>
    <sap:parameter name="HEADERDATA.ADDRESS_VAL_END_DATE"/>
    <sap:parameter name="HEADERDATA.CREATED_BY"/>
    <sap:parameter name="HEADERDATA.CREATED_AT"/>
    <sap:parameter name="HEADERDATA.CHANGED_BY"/>
    <sap:parameter name="HEADERDATA.CHANGED_AT"/>
    <sap:parameter name="HEADERDATAX.EMAIL_ADDRESS"/>
    <sap:parameter name="HEADERDATAX.PHONE_NUMBER"/>
    <sap:parameter name="HEADERDATAX.FAX_NUMBER"/>
    <sap:parameter name="HEADERDATAX.WEB_ADDRESS"/>
    <sap:parameter name="HEADERDATAX.BUILDING"/>
    <sap:parameter name="HEADERDATAX.COUNTRY"/>
    <sap:parameter name="HEADERDATAX.COMPANY_NAME"/>
    <sap:parameter name="HEADERDATAX.LEGAL_FORM"/>
    <sap:parameter name="BP_ID.BP_ID"/>
    <sap:resultChecker className="com.sybase.sap3.DefaultSAPOperationHandler"/>
    <sap:requireCommit>true</sap:requireCommit>
    </sap:function>
    </ds-meta-data>
    </ds-operation>
    </operation>
    <ds-meta-data xmlns:interaction="http://www.sybase.com/sup/ds/schema/deployment/core/interaction" xmlns:sap="http://www.sybase.com/sup/ds/schema/deployment/sap">
    <query name="updateQuery" xmlns="http://www.sybase.com/sup/ds/schema/deployment">
    <interaction:operation name="update"/>
    <interaction:map/>
    </query>
    </ds-meta-data>
    <operation name="getInputRecords_for_BusinessPartner" static="true" server-only="true" type="object*">
    <parameter name="userNameParameter" type="string"/>
    <parameter name="remoteIdParameter" type="string"/>
    <ds-operation>
    <input-record type="sap:BAPI_EPM_BP_GET_LIST_INPUT"/>
    </ds-operation>
    </operation>
    <ds-meta-data xmlns:interaction="http://www.sybase.com/sup/ds/schema/deployment/core/interaction" xmlns:sap="http://www.sybase.com/sup/ds/schema/deployment/sap">
    <query name="loadAllQuery" xmlns="http://www.sybase.com/sup/ds/schema/deployment">
    <interaction:operation name="loadAll"/>
    <interaction:map>
    <interaction:column name="BP_ID" mappedName="BPHEADERDATA.BP_ID"/>
    <interaction:column name="BP_ROLE" mappedName="BPHEADERDATA.BP_ROLE"/>
    <interaction:column name="EMAIL_ADDRESS" mappedName="BPHEADERDATA.EMAIL_ADDRESS"/>
    <interaction:column name="PHONE_NUMBER" mappedName="BPHEADERDATA.PHONE_NUMBER"/>
    <interaction:column name="FAX_NUMBER" mappedName="BPHEADERDATA.FAX_NUMBER"/>
    <interaction:column name="WEB_ADDRESS" mappedName="BPHEADERDATA.WEB_ADDRESS"/>
    <interaction:column name="COMPANY_NAME" mappedName="BPHEADERDATA.COMPANY_NAME"/>
    <interaction:column name="LEGAL_FORM" mappedName="BPHEADERDATA.LEGAL_FORM"/>
    <interaction:column name="CITY" mappedName="BPHEADERDATA.CITY"/>
    <interaction:column name="POSTAL_CODE" mappedName="BPHEADERDATA.POSTAL_CODE"/>
    <interaction:column name="STREET" mappedName="BPHEADERDATA.STREET"/>
    <interaction:column name="BUILDING" mappedName="BPHEADERDATA.BUILDING"/>
    <interaction:column name="COUNTRY" mappedName="BPHEADERDATA.COUNTRY"/>
    </interaction:map>
    </query>
    <operation name="loadAll" unmanaged="false" xmlns="http://www.sybase.com/sup/ds/schema/deployment">
    <sap:dataSource name="ERP_JCO"/>
    <sap:function name="BAPI_EPM_BP_GET_LIST">
    <sap:column key="BPHEADERDATA.BP_ID" name="BPHEADERDATA.BP_ID"/>
    <sap:column key="BPHEADERDATA.BP_ROLE" name="BPHEADERDATA.BP_ROLE"/>
    <sap:column key="BPHEADERDATA.EMAIL_ADDRESS" name="BPHEADERDATA.EMAIL_ADDRESS"/>
    <sap:column key="BPHEADERDATA.PHONE_NUMBER" name="BPHEADERDATA.PHONE_NUMBER"/>
    <sap:column key="BPHEADERDATA.FAX_NUMBER" name="BPHEADERDATA.FAX_NUMBER"/>
    <sap:column key="BPHEADERDATA.WEB_ADDRESS" name="BPHEADERDATA.WEB_ADDRESS"/>
    <sap:column key="BPHEADERDATA.COMPANY_NAME" name="BPHEADERDATA.COMPANY_NAME"/>
    <sap:column key="BPHEADERDATA.LEGAL_FORM" name="BPHEADERDATA.LEGAL_FORM"/>
    <sap:column key="BPHEADERDATA.CURRENCY_CODE" name="BPHEADERDATA.CURRENCY_CODE"/>
    <sap:column key="BPHEADERDATA.CITY" name="BPHEADERDATA.CITY"/>
    <sap:column key="BPHEADERDATA.POSTAL_CODE" name="BPHEADERDATA.POSTAL_CODE"/>
    <sap:column key="BPHEADERDATA.STREET" name="BPHEADERDATA.STREET"/>
    <sap:column key="BPHEADERDATA.BUILDING" name="BPHEADERDATA.BUILDING"/>
    <sap:column key="BPHEADERDATA.COUNTRY" name="BPHEADERDATA.COUNTRY"/>
    <sap:column key="BPHEADERDATA.ADDRESS_TYPE" name="BPHEADERDATA.ADDRESS_TYPE"/>
    <sap:column key="BPHEADERDATA.ADDRESS_VAL_START_DATE" name="BPHEADERDATA.ADDRESS_VAL_START_DATE"/>
    <sap:column key="BPHEADERDATA.ADDRESS_VAL_END_DATE" name="BPHEADERDATA.ADDRESS_VAL_END_DATE"/>
    <sap:column key="BPHEADERDATA.CREATED_BY" name="BPHEADERDATA.CREATED_BY"/>
    <sap:column key="BPHEADERDATA.CREATED_AT" name="BPHEADERDATA.CREATED_AT"/>
    <sap:column key="BPHEADERDATA.CHANGED_BY" name="BPHEADERDATA.CHANGED_BY"/>
    <sap:column key="BPHEADERDATA.CHANGED_AT" name="BPHEADERDATA.CHANGED_AT"/>
    <sap:resultChecker className="com.sybase.sap3.DefaultSAPOperationHandler"/>
    <sap:requireCommit>true</sap:requireCommit>
    </sap:function>
    </operation>
    <implementation xmlns="http://www.sybase.com/sup/ds/schema/deployment">
    <interaction:virtualTable loadAllQuery="loadAllQuery"/>
    </implementation>
    </ds-meta-data>
    <subscribe>
    <download-data>
    <synchronization-parameter name="CountryFilter" type="string?" max-length="3" default-value="" mapped-to-load="false" mapped-name="COUNTRY"/>
    <sql>SELECT x.* FROM BusinessPartner x WHERE ( (x.COUNTRY=:CountryFilter ) OR ( ( x.COUNTRY IS NULL ) AND (:CountryFilter IS NULL ) ) )</sql>
    </download-data>
    </subscribe>
    </entity>
    <ds-meta-data>
    <dep:cache name="Default" xmlns:dep="http://www.sybase.com/sup/ds/schema/deployment">
    <dep:loadGroup>
    <dep:inputRecordFactory class="MigrationPoC.server.BusinessPartner" method="getInputRecords_for_BusinessPartner"/>
    <dep:partition>
    <dep:queryReference virtualTableName="BusinessPartner" queryName="loadAllQuery"/>
    <dep:key/>
    </dep:partition>
    </dep:loadGroup>
    <dep:cacheAffectingOperation name="update" rootVirtualTableName="BusinessPartner" effect="upsert">
    <dep:queryReference virtualTableName="BusinessPartner" queryName="updateQuery"/>
    </dep:cacheAffectingOperation>
    <dep:cachedTable virtualTableName="BusinessPartner"/>
    <dep:policy>
    <dep:onDemand resultCache="false" coherenceWindow="PT0S"/>
    </dep:policy>
    </dep:cache>
    </ds-meta-data>
    </package>
  3. Open terminal in SAP Business Application Studio (via “Terminal” > “New Terminal”) and run the following
    command:

    /tmp/vscode-unpacked/vsc-extension-mbt-1.9.0.vsix/extension/resources/server-odata-sdk/bin/afx-to-csdl.sh 4.0 deployment-unit.xml ./
            
    • Executing the script will generate an OData V4 (you can use V2 instead if you prefer) CSDL file
      including annotations reflecting the logic and interfaces translated from the MBO packageOpen terminal
      in SAP Business Application Studio (via “Terminal” > “New Terminal”) and run the following command:

      Due to version dependency the path of “vsc-extension-mbt-1.9.0.vsix” might change – in case
      you can figure out the correct path via terminal using auto-complete or by executing the following
      in Terminal:

      find /tmp/vscode-unpacked -name afx-to-csdl.sh -print
      
  4. If you are using your own model, you might want to go through your metadata and check for errors or improvable parts. MBT annotations are more flexible than MBO in several areas.

  5. Make sure that all destinations exist in your environment which are targeting other systems from CSDL annotations. In MBT perspective, those are called “Entity Handlers” and can represent refresh- or write-operations on entity or entity-set level for http, JCo or JDBC. As JCo is used often to refresh data in MBO, this example is focusing on JCo. e.g.
    <Annotation Term="JCO.Destination" xmlns="http://docs.oasis-open.org/odata/ns/edm" String="ERP_JCO"/>
    

    Further information about entity handlers and bindings is available in the documentation for MBT, Cache Databases

    • In SAP BTP environment, e.g. the service given reference will require an SAP BTP destination of type “RFC” to be available with the name “ERP_JCO”. If you do not have an ABAP platform-based system (e.g. SAP S/4HANA or SAP Business Suite) that you can connect via SAP Cloud Connector, you can also use the following dummy destination for this purpose:
    • If you do not have a system available to attach, you can use the following destination properties (copy to file and import as destination in SAP Business Technology Platform Cockpit) which will not actually work, but suffice for the service to not initially crash
    jco.destination.proxy_type=Internet
    jco.destination.description=Dummy - proxy type internet is not supported for this system type
    Name=ERP_JCO
    jco.client.client=002
    jco.client.tls_trust_all=1
    Type=RFC
    jco.client.wsport=443
    jco.client.wshost=sapes5.sapdevcenter.com
    
    • In SAP BTP Cloud Foundry environment, in order use a JCo destination, you will have to provide the environment variable “USE_JCO”: true in the manifest as well as bind service instances for both destination and connectivity.

      Therefore create service instances either via Admin Cockpit or via Terminal:

              cf create-service destination lite mbomigrationdemo-destination
              cf create-service connectivity lite mbomigrationdemo-connectivity

      And make sure your manifest.yml finally looks similar to the following:

      
      ---
      applications:
        - buildpack: sap_java_buildpack
          name: d00xxxxxtrial_mboDemo
          path: target/odata-service-1.0.0.war
          env:    
            SET_LOGGING_LEVEL: '{odata: TRACE, sap.xs.console: TRACE, sap.xs.odata: TRACE}'
            TARGET_RUNTIME: tomee7
            USE_JCO: true
          services:    
            - mbomigrationdemo-xsuaa
            - mbomigrationdemo-destination
            - mbomigrationdemo-connectivity
        - name: d00xxxxxtrial_mboDemo-approuter
          path: approuter
          buildpacks:    
            - nodejs_buildpack
          memory: 128M
          services:    
            - mbomigrationdemo-xsuaa
          env:
            destinations: >
              [
                {
                  "name":"odata",
                  "url":"https://d00xxxxxtrialmbodemo.cfapps.eu10.hana.ondemand.com",
                  "forwardAuthToken": true
                }
              ]
      
    • In VS Code, it will be required to add dependencies to the local web server as well as provide JCo configuration
  6. Verify if any warning occurred during data model conversion. This might happen if e.g. one of the followinglimitations applies:
    • Entities with only a generated key and no alternate-key will be ignored
    • Operation parameters added as non-attributes cannot be mapped to an input record

If you see such or similar warnings or errors, you can fix them in the AFX file and re-migrate with the “-overwrite” option. Alternatively, after getting understanding of MBT-based Cache-Databases you can perform the changes manually in the CSDL.

Depending on the complexity of download logic in the MBO model, you might notice that in the converted OData CSDL document, entities like ClientRegistrationSet and multiple “Filter”-entities (annotated with SQL.ClientFilter) will appear- marked with specific annotations and required for reflecting the logic of download queries. Those entities should be served before first synchronisation.

It can be a good practice to simplify the data model by unifying ClientFilter -related entities – in MBO there had to be an own Filter record for any entity using it in the download query – even if all of them had to store the same value – with MBT-based services it is possible to unify and re-use them across entities. This can reduce data model and onboarding complexity on client applications for larger models.

After completing the migration, you can start developing your client. In case you to give it a try with SAP Mobile Services, Mobile Development Kit, there is another tutorial that you may follow as an introduction:
Onboard an MDK Client to Your OData Cache Database

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.