Persistent names in M-Business Anywhere applications

In HTML, when control transfers to a new page, all handles to allocated JavaScript objects from the old page are lost. For example, in main.html, you have a M-Business Anywhere database connection object:

conn = dbMgr.openConnection("...");

If you click a link in main.html and it takes you to a different page (for example: insert.html), you cannot find the object named "conn" in insert.html. To get the connection object back, you may have to call dbMgr.openConnection("...") again. However, you do not have to do this since the connection object is still in memory, you have only lost the JavaScript handle to it.

This is why there is a persistName argument in all the M-Business Anywhere API calls to DataManager, Connection, ULTable, PreparedStatement, or ResultSet. For example, when the M-Business Anywhere runtime receives a call from JavaScript for an UltraLite connection object, M-Business Anywhere first checks to see if a connection object exists in memory that has the same persistName. If the runtime can find a matching object, it will return that connection object. Otherwise, M-Business Anywhere goes through the normal procedure to make a new UltraLite database connection and return it.

Using persistent names

There are two types of hierarchy among M-Business Anywhere objects. They both start with DatabaseManager and Connection:

To retrieve any of these M-Business Anywhere objects with a persistent name, you have to retrieve the top-level object with a persistent name, and then all the upper level M-Business Anywhere objects along the hierarchy tree until the one you want.

For example, if you want to retrieve an existing ULTable object from insert.html, you need to give a persistent name to dbMgr, conn, and table objects in main.html, and then use persistent names in insert.html to get all of them back:

Code segment for main.html:

var dbMgr = CreateObject( "iAnywhere.UltraLite.DatabaseManager.simple" ); 
// "simple" is the persistent name here. A real database manager object is allocated

var conn = dbMgr.openConnection( "CON=simple_con;..." ); 
// "simple_con" is the persistent name here. A real database connection is made.

var custTable = conn.getTable( "ULCustomer", "simpleCustTable" ); 
// a real table is allocated

Code segment for insert.html:

var dbMgr = CreateObject( "iAnywhere.UltraLite.DatabaseManager.simple" ); 
// "simple" is the persistent name here. 
// The allocated database manager object from main.html is returned

var conn = dbMgr.openConnection( "CON=simple_con;..." ); 
// "simple_con" is the persistent name here. 
// The existing connection object from memory is returned.

var custTable = conn.getTable( "ULCustomer", "simpleCustTable" ); 
// the existing table object is returned.

var newTable = conn.getTable( "ULOrder", "simpleOrderTable" ); 
// since there is no order table from main.html, 
// it does not exist in memory. A real order table object is allocated.
Using persistent names correctly

Put the commonly used code in a JavaScript file. Since most HTML pages of an M-Business Anywhere application need to refer to DatabaseManager, Connection, and some major ULTable objects, it is convenient to put the code that creates them (or retrieves them with a persistent name) in a common JavaScript file, and include this file at the top of HTML pages that use them. Both M-Business Anywhere "simple" and "CustDB" sample programs demonstrate how to do this.

Close the object if you do not plan to use the object from another page. If the M-Business Anywhere application only has one HTML page, then there is no need to have persistent names. The persistent name argument can be set to NULL. On the other hand, if each HTML page has many opened PreparedStatement and ResultSet objects, then the developer needs to balance between the convenience of having them in memory to retrieve them easily with a persistent name from another html page, and wasted memory usage because these objects are always around. For example, suppose you have 5 PreparedStatement objects and 10 ResultSet objects created in main.html. They are occupying a significant amount of memory. When the application jumps to insert.html, if you only need to refer to some of these objects with a persistent name, then the objects that are not needed anymore are wasting memory. If you try to create new PreparedStatement and ResultSet objects in insert.html, you may run out of memory. The solution is to explicitly close those PreparedStatement object or ResultSet object at the end of main.html if you are sure you do not need them from insert.html.

The state of each M-Business Anywhere object is preserved when it is retrieved with a persistent name. If you have a persistent ULTable object from page 1, when you call openTable method from page 2 using the same persistent name, you get the exact ULtable object back with the same state as the one from page 1. If the cursor is on the nth row of the table when you leave page 1, the cursor will be still on the nth row when you get it back in page 2. It will not be "before first row".

Be careful using the persistent name on ResultSet. When there are place holders on the PreparedStatement, you need to be very careful about whether you want to give a persistent name to the ResultSet. For example, in main.html you have the following code:

var OrderStmt = Connection.prepareStatement(
"SELECT order_id, disc, quant FROM ULOrder WHERE order_id = ?", 
"order_query_stmt" );

OrderStmt.setInt(1, 5000);

var OrderResultSet = OrderStmt.executeQuery( "order_query_result" );

Then from insert.html, you want the same ResultSet object, you must do the following:

var OrderStmt = Connection.prepareStatement(
"SELECT order_id, disc, quant FROM ULOrder WHERE order_id = ?", 
"order_query_stmt" );

//OrderStmt.setInt(1, 5000); // no need to do this since both the OrderStmt and 
OrderResultSet are retrieve from "cache" without any SQL statement being 
actually executed

var OrderResultSet = OrderStmt.executeQuery( "order_query_result" );

This OrderResultSet object contains the same result as the "order_id" set to 5000.

However, consider a different situation. You want the same PreparedStatement because you want to do the same query on the Order Table. But you want to query with an order ID other than 5000. In this case, you can assign a persistent name to the PreparedStatement, but you don't need a persistent name on the ResultSet. Since the order id is different this time, the result set will be different from the previous one. In main.html, you still do the following:

var OrderStmt = Connection.prepareStatement(
"SELECT order_id, disc, quant FROM ULOrder WHERE order_id = ?", 
"order_query_stmt" ); // with persistent name

OrderStmt.setInt(1, 5000);

var OrderResultSet = OrderStmt.executeQuery( null ); // notice here, no persistent name

In insert.html, you do the following to get a new ResultSet:

var OrderStmt = Connection.prepareStatement(
"SELECT order_id, disc, quant FROM ULOrder WHERE order_id = ?", 
"order_query_stmt" ); // get the prepared statement from memory with persistent name

OrderStmt.setInt(1, 6000); // set a different place holder value

var OrderResultSet = OrderStmt.executeQuery( null ); // a real query is executed 
here!

In the example above, since the place holder value is different, or some other operation is performed on the Order table that you expect the returned result set will be different, you do not use persistent name on the ResultSet when calling executeQuery.