In addition to restrictions, this section documents workarounds and suggestions that may be useful to product users.
Home createFromKey:
When creating a new object, you can create it with the Home createFromKey: method. If that key contains relationships (really the keys of the related objects) then the related objects cannot be new objects. If you want to set a relationship to a new object, you should use create and then set the relationships with the new object (NOT the key), or use the createWith:with: helpers on the homes. The reason behind these restrictions is that the key of a new object is not guaranteed to be permanent, so we do not support lookup of a new instance by key, therefore a relationship to that new object by key alone can't be resolved. For example:
| b1 newBranch c bc | b1 := VapBankBranchHome singleton findByBranchNumber:'BR001'. newBranch := VapBankBranchHome singleton createWithBranchNumber:'BR999'. c := VapCurrencyHome findByCurrencyType: 'CRC01'. "Relate two existing objects: Works OK" bc := VapBranchCurrencyHome createForBranch: b1 currency: c. "Relate one existing object and one new using helper: Sets relationshipvalue directly, Works OK" bc := VapBranchCurrencyHome createForBranch: newBranch currency: c. "Relate one existing object and one new using createFromKey: Does not work!" bc := VapBranchCurrencyHome createFromKey: (VapBankBranchKey with: newBranch key with: c key). "also: until newBranch is committed to the data store and the Shared Transaction, you can't find it by key, ala: VapBankBranchHome singleton findByBranchNumber: 'BR999'. "
Residual instance variables on model regeneration
If you delete class attributes in a model for which you have already generated code, and then regenerate the model, you may encounter the following problem: your instance variables represented by the attributes you deleted will still exist in the class, however their getter and setter methods will be properly deleted.
DBCS character text field entry
You cannot enter DBCS characters in ObjectExtender browsers and tools except for one case:
In addition to Physical name, there is a corresponding (optional) logical name field (Name) for tables. If you import a schema from a database, which has double-byte characters, enter logical names for each physical name, you must enter single-byte characters for the logical name.
Mapping, relationships, and preload limitations
Inheritance Mappings
Abstract Mapped Classes
Relationships
Class Mapped to Multiple Tables
Preloading. There is a known bug with preloading relationships on a class whose target classes are mapped to the same class (or inheritance hierarchy). The query generated is incorrect. This occurs in the following scenarios:
Single character data and vendor DB drivers
Various vendors' database drivers treat single-character data differently. Some will return a Character, some will return a String of length one. To be safe, if an application may run with multiple drivers, type Char(1) fields as strings, and the VapCharToString converter will guarantee that a string will always be returned.
IC instruction not preloaded
For all VisualAge users using ICs, they must load the following two config maps before using ICs, 1) Envy/Packager IC Instructions, and 2) VisualAge IC Instructions
For ObjectExtender users, you must load one more instruction: VisualAge Persistence IC Instructions
These instructions must be loaded in this order.
Composed object does not make aggregate dirty
When using composed objects, the aggregate object is not marked "dirty" in a partial update scenario. For example, TstCustomer object has a name which is a composed object. When an update partial name operation is performed (first name or last name) the object is not marked dirty, so the changed object will not be written into the data store. To force the change, you must change the other attribute of the object.
Global reset does not clean up database connections
If you attempt to clean up database connections using the "Global ObjectExtender Reset", and you get an unknown abtError, you may still have a dead connection to the DB. One workaround for this is to evaluate the following:
AbtDbmSystem startUp
Generate models first before other code-gens
As a general rule, always generate code for models before generating services code or stub code for schema or local image persistence. If you generate code without a model present a walkback will occur stating that the model is missing.
Backwards 1:1 relationships
If you have backwards 1:1 relationships, you must always regenerate the services after generating the model. Model generation assumes that all 1:1 relationships are forwards, service generation uses the maps to correct those which were backwards.
When Changing composer types
If you have a complex attribute map, and you want to change the Composer type, you need to delete the Complex attribute map from the Map Browser and recreate it in the Property Map Editor.
Specialization for cascade delete
A specialization of BusinessObject>>#abtRemove is available for cascade delete operations. The cascade responsibility is divided between the two remove methods. #abtRemove is sent by the application to the root object being deleted. This method can be overridden to disconnect the root object from its parent object. The default implementation of #abtRemove just calls #markRemoved. #markRemoved should be specialized to perform any disconnects and cascades which an object should perform whether or not it is the root. It should not disconnect from its parent object here. It should not disconnect any connections to child objects, since these connections are required to perform operation sorting for referential integrity constraints. An example might go like this:
VapCustomer>>#abtRemove self bankBranch: nil. "disconnect from parent" super #abtRemove "calls #markRemoved" VapCustomer>>#markRemoved self accounts do: [:acc | acc markRemoved]. "cascades to transactions, etc." self homeAddress markRemoved. self billingAddress markRemoved. "you could also disconnect any non-aggregate associations here"
Foreign keys used in 1-1 relationships
If foreign keys are used for 1-1 relationships, the association must be navigable. For example, suppose you have the following :
Model: Customer <-------> Address 1. homeAddress 2. billingAddress Schema: Customer table contains homeAddress and billingAddress columns which are foreign keys to Address table.
You must then define both model associations navigable. Otherwise, on inserting customer, it will not insert the address first, and you will get an insert customer error because the address parent key does not exist.
Service Generation should generate #executeSingleUpdate: for No key object
The problem occurs when a model class has only properties which are part of its OID.
An association object, modeling a join table, is a good example.
Say you have a model class called BranchToCurrency which is an association between Branch and Currency, its only properties are two associations, and these two associations make up the OID of the BranchToCurrency object. Since the database row only has key fields, there are no updatable fields, and our UPDATE query will not work properly.
The workaround is to override the service method #executeSingleUpdate: to do nothing. The application developer should structure their use of these kinds of objects so that the application never tries to update one, always adding or removing new instances rather than changing an existing one. The override above is just to catch a case where the app accidentally updates an object, maybe by disconnecting a related object.
Pre-req for user-defined composers
Model and service applications which use Composers need to make sure their pre-reqs are updated to include their application which define any user-defined model and composers. For example, if a model has a property which is a Name, and the maps specify that a composer called NameComposer should be used, then the generated model application must pre-req the application defining Name, and the generated service app must pre-req the application defining NameComposer.
No converter for AbtMonetaryAmount
A converter for AbtMonetaryAmount is not provided, use ScaledDecimal instead.
Workaround for Sun core exiting VisualAge ObjectExtender application
On Soliaris platforms, if you encounter a core dump on exiting VisualAge ObjectExtender application (runtime), the workaround is to comment the method #shutDown in class PlatformLibrary, then re-package the application.