WS-AppServer BusObject Mapping (2)

WS-AppServer BusObject Mapping (2)

This post shows you about mapping between DB and BusObjects. Suppose we have next 2 tables in our DB:

Upper case is used as per Oracle convention, and the tables names do have a prefix to indicate the application the tables belong to (customer practice). For our WS-AppServer generated standard classes, we can provide the mapped names, both on class and attribute level, achieving camel case and skipping the ‘CIM’ prefix:

Result is, our Java classes and WSDL have the naming as camel case, and getting a customer gives next result:

<tuple>
 <old>
  <Customer>
   <CustomerID>1</CustomerID>
   <Name>Coleman Ldt</Name>
   <Address>Antony drive 122, NY</Address>
  </Customer>
 </old>
</tuple>

Let’s see how this is achieved in Java. First, we execute a plain query and get the result which is by default an AnonymousBusObject.

Result:

<CIM_CUSTOMER>
 <CUSTOMER_ID>1</CUSTOMER_ID>
 <NAME>Coleman Ldt</NAME>
 <ADDRESS>Antory drive 122, NY</ADDRESS>
</CIM_CUSTOMER>

Now, we use the setResultClass() method:

Because of this, not only will the query.getObject() now return an object of class Customer, but also it will know now from the ClassInfo on how to do the mapping. In CustomerBase.java:

In case you want to have full control yourself, you can set a so called mapping strategy by utilizing the customizeClassInfo() event handler:

To set the mapping strategy, supply an instance of a class which implements the ImapClassStrategy interface. There are 3 standard mapping strategies with corresponding classes:

  • TrivialStrategy: enables table-class name mapping
  • NameMappingStrategy: for table-class and column-attribute mapping with help of a mapping array
  • DefaultStrategy: maps both class-table as well as attributes-columns. Supply an instance of a class which implements the ImapAttributeStrategy interface (by which you can map both class-table as well as attributes-columns), or don’t supply any instance and let WS-AppServer fall back on DefaultAttributeStrategy (for attributes) and in case no class-table mapping is known, WsApps falls back on the TrivialStrategy for this.

Setting the mapping strategy by customizing the class info can be applied for standard and inherited classes, and will take care of mapping for both getting data as well as updating (reverse mapping).

Now instead of a standard class, we have a custom class with next layout (join of BankAccount and Customer):

<AccountFull>
 <AccountID unique="true">i8</AccountID>
 <CustomerID>i8</CustomerID>
 <CustomerName>string</CustomerName>
 <CustomerAddress>string</CustomerAddress>
 <BondType>i4</BondType>
 <Dividend>r4</Dividend>
</AccountFull>

For custom classes, we can only specify the class and attribute names in the repository. The mapping can be achieved by using the setResultMapping() method:

Attribute mapping can effectively also be achieved by specifying the individual columns in the select-clause, and using the AS-clause (select CIM_BANKACCOUNT.ACCOUNT_ID as AccountID, etc). Notice though, only upon using setResultMapping(), WS-AppServer will also map the class name (query.setResultMapping(QueryObject.MAP_CUSTOM, null)).

In case you only need to map a subset, leaving the other attributes unchanged, you can use “*”:

This only works for this method setResultMapping().

To conclude for now, let’s explore the nested scenario:

<AccountFull>
 <AccountID>1</AccountID>
 <CustomerID>2</CustomerID>
 <BondType>1</BondType>
 <Dividend>2456</Dividend>
 <Customer>
   <CustomerID>2</CustomerID>
   <Name>Howard Ldt</Name>
   <Address>Hovard road 2412, AD</Address>
 </Customer>
</AccountFull>

which can be achieved like this:

In next post we will see some more advanced mapping scenario’s.

2 COMMENTS

comments user
Tim Bottelbergs

Hi Karel,

Would the nested scenario also work for multiple inner objects? For example, if there would be a list of customers in the “AccountFull” object? Or when we have an “Order” object containing “Order Lines”?

Regards,

Tim

    comments user
    Karel

    Hi Tim,
    Certainly. For occurrence-*, your code will remain the same, using the same query.getObject() method at the end, and the resulting set of OrderLine records will populate as multiple inner objects to the parent object.


    String queryText = "select * from ORDER where ORDER.ORDER_ID = :OrderID ";
    QueryObject query = new QueryObject(queryText);
    query.addParameter("OrderID", "ORDER.ORDER_ID", QueryObject.PARAM_INT, new Long(OrderID));
    String associationQueryText = "select * from ORDER_LINE where ORDER_LINE.ORDER_ID = :OrderID ";
    AssociationQueryObject associationQuery = new AssociationQueryObject(associationQueryText, "ORDER", "ORDER_LINE");
    associationQuery.addParameter("OrderID", "ORDER.ORDER_ID", QueryObject.PARAM_INT, null);
    query.addAssociationQuery(associationQuery);
    query.setResultClass(FullOrder.class);
    FullOrder fullOrder = (FullOrder)query.getObject();

    Regards,
    Karel.

Leave a Reply

Your email address will not be published. Required fields are marked *