The data-aware dbSwing and JBCL controls bind to DataExpress datasets. The DataExpress paradigm cleanly separates data sources from datasets, through providers and resolvers, making DataExpress ideal for multi-tier applications.
After data is provided to an application or a data module, you can view and work with the data locally in data-aware controls. You can store your data to local memory (MemoryStore) or to a local file (DataStore). When you want to save the changes back to your database, you must resolve the data.
By default, once data is loaded into a JBuilder component the storage mechanism is in-memory storage through the use of a MemoryStore. Alternate storage systems such as the DataStore are allowed by setting the StorageDataSet object's store property. (Currently MemoryStore and DataStore/DataStoreConnection are the only implementations of the Store interface required by the store property.)
The main advantages of DataStore over MemoryStore are transaction semantics, SQL support, and persistence, which enable offline computing. A DataStore will remember the rows fetched in a table, even after the application has been terminated and restarted. In addition, you can increase the performance of any application with large StorageDataSets. StorageDataSets using MemoryStore have a small performance edge over DataStore for a small number of rows; however, DataStore stores data and indexes in an extremely compact format. As the number of rows in a StorageDataSet increases, using a DataStore is much more performant and requires much less memory than using a MemoryStore.
Whether the data's storage is MemoryStore or DataStore often does not effect how you work with a StorageDataSet or other data-aware controls connected to the StorageDataSet. However, storing Java objects in columns does require the use of Java serialization (java.io.Serializable). If this is not possible, you cannot use DataStore components and should use the default in-memory storage mechanism.
Caching and persisting StorageDataSets in a DataStore is accomplished through the three property settings discussed in "Connecting to a DataStore with StorageDataSet". Persisting data from a provider usually involves the two subclasses of StorageDataSet with predefined providers: QueryDataSet (which uses QueryProvider) and ProcedureDataSet (which uses ProcedureProvider).
To store and persist the data from one of those StorageDataSets in a DataStore using the design tools:
This tutorial provides the steps for creating an application that uses a DataStore component to enable offline editing of data. The server database will be a sample DataStore file, employee.jds
, accessed through the DataStore Server. Do not confuse this file with the DataStore used for persistence. Locate the sample file before beginning (it is installed in samples/JDataStore/datastores
).
PersistFrame.java
.
employee.jds
file in place of d:/jbuilder
in the URL:
Click the Test Connection button to check that the connection properties have been correctly set. When the connection is successful, click OK.
Adding a DataStoreConnection component writes an import statement for the datastore package to your code, and adds the "Datastore 3.1" library to your project properties if it was not already listed.
.jds
. Click OK.
Note: The Designer will automatically create this DataStore file for you when it is connected to the StorageDataSet, so that the tools work fully. When you run the application, the DataStore file will already be there. But if you run the application on another computer, the DataStore file won't be there. You will have to add extra code to create the DataStore file if necessary, as shown in "Creating a DataStore file".
Open the query property editor for the QueryDataSet component in the Inspector and set the following properties:
Click Test query to ensure that the query is runnable. When the gray area beneath the button indicates Success
, click OK to close the dialog box.
employeeData
.
Add a DBDisposeMonitor component from the More dbSwing tab to the component tree. Set its dataAwareComponentContainer property to this.
PersistApp.java
.
In the running application, make some changes to the data and click the Post button on the navigator to save the changes to the DataStore file (the persistence DataStore specified in step 7 above). Changes are also saved to the file when you move off of a row, just as they are with an in-memory data set (MemoryStore).
Note: A data set in a DataStore can have tens or hundreds of thousands of rows. Handling that much data using an in-memory data set would have an undesirable impact on application performance.
Close the application and run it again. You see the data as you edited it in the previous run. This, of course, is very different from the behavior of an in-memory data set. If you want, you can exit the application, shut down the DataStore Server, and run the application again. Without any connection to the SQL database, you can continue to view and edit data in the DataStore. This would be especially useful if you want to work with data offline, such as at home or on an airplane.
So far in the tutorial, nothing has been saved back to the SQL database on the server. On the JdbNavToolbar,
Options set in the queryDescriptor also have an effect on how data is stored, saved, and refreshed. In the queryDescriptor in this example, the Execute Query Immediately When Opened option is selected. This option indicates how data is loaded into the DataStore file when the application was first run. On subsequent runs, the execution of the query is suppressed, because the data set is found in the DataStore file instead of on the server. As a result,
The Execute Query Immediately When Opened option is not allowed to overwrite existing data (unless the StorageDataSet.refresh method is called explicitly). This means that you can safely close and reopen a data set to change property settings in either a MemoryStore or in a DataStore without losing editing changes.
Once you've got data in the DataStore file, you can run this application and edit data whether the database server is available or not. When you are working offline, you have to remember not to click the navigator's Save or Refresh button; you will get an exception because the attempt to connect will fail, but you won't lose any of the changes you have made.
The Column Designer in the JBuilder UI designer provides support for moving, deleting, and inserting columns. Column data types can also be changed. When the data type of a Column component in a StorageDataSet that is bound to a DataStore is changed, type coercions occur when going from one type to another.
To activate the Column Designer,
This designer works for StorageDataSets that are using a MemoryStore or a DataStore. MemoryStore performs all operations instantly. When a Column data type is changed, MemoryStore does not convert data values to the new data type. The old values are lost.
DataStore does not perform the move/insert/delete/change type operations on StorageDataSets immediately. The structural change is noted inside the DataStore directory as a "pending" operation. The StorageDataSet.getNeedsRestructure method returns true when there is a "pending" restructure operation. A StorageDataSet with pending structural changes can still be used.
To make a pending restructure operation take effect, click the Restructure toolbar button in the Column Designer. You can also cause a restructure operation to happen programmatically by calling the StorageDataSet.restructure method.
The restructure method can be used even when there are no pending structural changes to repair or compact a StorageDataSet and its associated indexes. (See the DataStoreConnection.copyStreams method for another way of repairing damaged streams.)
When the data type of a Column component in a StorageDataSet that is bound to a DataStore is changed, type coercions occur when going from one type to another. The following table describes what happens when a data type is coerced to another data type. The data types on the left indicate the original data type of the Column with the data types listed along the top of the table indicating the new data type of the Column.
Where the table values represent the following:
Many DataSets, like QueryDataSet and ProcedureDataSet, obtain their structure and row data from a SQL server. But there is also the need to add columns to these DataSets or to create standalone tables. This can be accomplished with the JBuilder Column Designer. DataSet columns can be changed, deleted, moved, and added instantly at design time. The DataStore uses a mapping table to provide an illusion that each structural operation has occurred. When all structural changes are complete, the Restructure button can be pressed.
When the UI Designer is activated while a StorageDataSet node is selected, the columns for that node are displayed in a grid on the design surface. A tool bar for adding, deleting, moving up, moving down, and restructuring the data set is displayed above the grid.
Regardless of whether a DataStore is used, columns provided by a query or procedure must be merged with columns defined in code. When a DataStore is being used, this merge still must happen, followed by a merge between the resulting column list and the columns found in the data set in the store.
Ideally, columns in the DataStore are the same as those provided by the merge. But when developing an application, there are often changes, and even a production application sometimes has to change. You can continue to use a data set in a DataStore when the columns in the DataStore are not the same as those from the application/provider merge. The provide operation will automatically restructure the table after merging.
If you change a data set's structure in the Designer instead of editing the source code, the DataStore tracks the changes. This makes the merge between application/provider columns and DataStore columns easier. For instance, if you change the name of a calculated column through the Designer, you can continue to display and edit values in the column, because the DataStore can map the old column name to the new one. If you make the same change in code, the DataStore can only determine that one column was deleted and another was added. The DataStore will not recognize that the column was renamed. So the "deleted" column will not be displayed, and the "added" column will be empty and non-editable.
The following list provides more information for different types of data set structure changes.
Restructuring also packs the dataset and deletes indexes. The indexes will be rebuilt when needed.
pubsweb@borland.com
Copyright © 1999, Inprise Corporation. All rights reserved.