Oracle9iAS TopLink Troubleshooting Guide Release 2 (9.0.3) Part Number B10068-01 |
|
This section contains frequently asked questions and their answers. The TopLink documentation set contains more detailed information on each of these items.
The FAQs are grouped in the following categories:
TopLink is an object-relational framework, which facilitates the construction of an object-oriented system that can store its objects/data in a relational database. The framework provides facilities, which allow the developer to deal primarily with objects independently of their underlying relational structure.
TopLink is intended for development projects where rapid development, code maintenance, flexibility, and performance are a priority. TopLink provides a proven framework with many advanced features, which make the many tough issues surrounding object-relational development manageable.
Refer to the Oracle9iAS TopLink: Getting Started Guide for detailed information.
TopLink is composed of two main logical components: a development and a runtime component.
The development component provides a graphical user interface and a class library (tl_tools.jar
). These development tools allow the developer to interact with both the domain classes and the relational database in order to construct their persistent mappings.
The runtime component of TopLink is a series class libraries. The core TopLink classes are contained in tl_core.jar
, and the enterprise classes are contained in tl_x.jar
. The tl_sdk.jar
, tl_sdkx.jar
, and xerces.jar
libraries are used if you will be reading TopLink Mapping Workbench-generated XML files, or using the TopLink SDK.
The toplink.jar
file contains all the TopLink runtime classes from tl_core.jar
, tl_x.jar
, tl_sdk.jar
, tl_sdkx.jar
, and tl_tools.jar
.
The TopLink CMP for BEA WebLogic and TopLink CMP for IBM WebSphere Foundation Libraries each contain an additional library (tl_wlsx.jar
, and tl_wasx.jar
, respectively).
No, TopLink is not an application or EJB server - it is a pure Java class library which provides an object-relational framework. Since it is certified 100% Pure Java it is capable of running within any certified Java environment. With the enterprise classes, TopLink integrates with application and EJB servers.
TopLink also provides extensions products that integrate with EJB servers to provide Container Managed Persistence (CMP) for Entity Beans.
Following the installation of TopLink you must configure your development system to make use of the TopLink classes as well as allow TopLink to access the core Java classes, JVM, and your domain classes.
When modifying your PATH and CLASSPATH variables, ensure you are using the environment variables.
tl_core.jar
and tl_tools.jar
) are in your CLASSPATH.
TopLink can communicate with any relational database which has a JDBC-compliant driver available such as Oracle, DB2, Sybase, SQL Server, Informix, Cloudscape, and Access. TopLink supports both the JDBC 1.x and 2.0 standards.
TopLink does not force the developer to subclass from one of its classes or use special types to maintain relationships. You could build a domain model to map persistently which has no dependencies on TopLink. TopLink does however require access to instantiate the persistent classes as well as access to get and set values within these objects.
In order to instantiate your objects, TopLink requires either a zero argument public constructor or a factory object and a method to invoke to get a new instance.
In order to gain access to the fields of a persistent class, TopLink requires public get and set methods or public fields. Starting with JDK 1.2 or Java 2 TopLink can access protected or private fields, provided the environment has been configured to grant TopLink access.
TopLink automatically converts database values for the following Java types: String, Number, BigDecimal, BigInteger, Long, long, Integer, int, Float, float, Double, double, Byte, byte, Short, short, java.util.Date, java.sql.Date, Time, Timestamp, Calendar, byte[], Boolean,
and boolean
.
For other types, you must use an object-type, type conversion, or transformation mapping; or transform the value in the direct-to-field get/set methods.
Because TopLink uses a metadata architecture it does not need to generate any code to enable your application's persistence.
TopLink can generate:
The TopLink Mapping Workbench can generate:
The TopLink CMP for BEA WebLogic and TopLink CMP for IBM WebSphere Foundation Libraries are supersets of the TopLink for Java Foundation Library. You get all of the same functionality. However, these libraries also allow you to use TopLink with container-managed persistence (CMP) Entity Beans on BEA WebLogic and IBM WebSphere application servers.
TopLink for Java Foundation Library can run in any application server running in a Java Virtual Machine. You can use regular Java objects or integrate with bean-managed persistence (BMP) Entity Beans. You only need the specialized TopLink CMP for IBM WebSphere or BEA WebLogic Foundation Libraries if you are going to use TopLink with container-managed persistence (CMP) Entity Beans in those servers.
TopLink provides a complete set of mappings for both direct and reference relationships. This allows developers to map from the object model to the relational model without one model dictating to the other. The oracle.toplink.mappings
package contains the following:
TopLink comes with class libraries for Java 2 (JDK 1.2 and higher). With Java 2 TopLink can access non-public fields and/or methods. Grant the ReflectPermission
permission to TopLink to "suppress default Java language access control checks when using reflected members and constructors." The granting of permissions is done via the security policy file using the policy tool application.
See the internet site http://java.sun.com/products/jdk/1.2/docs/guide/security/index.html for more information.
Normally no, since primitive types in Java cannot be null. If the field value is null, TopLink will try to assign null to a primitive, which raises a NullPointerException
.
The easiest way to avoid this problem is to ensure all of the database fields that store primitive values cannot be null. You could also configure the mapping to use a default value for null by using the NullValue
property on all direct mappings:
mapping.setNullValue(new Integer(0));
You can also configure NullValue
for all mappings and descriptors on the DatabaseLogin
:
login.setDefaultNullValue(int.class, new Integer(0));
Yes, you can define mappings that reference interfaces instead of classes. Interfaces can be defined for a single class or for a set of implementors. Querying on the interface will query each of the implementors.
TopLink provides the ability to define any reference mapping (1:1, 1:M, and M:M) as privately owned. This means that when the source object is written or deleted so should all of its privately owned parts.
Yes, provided that only one of the mappings is made writable. TopLink requires one writable mapping for which it will retrieve the required value from the object when constructing the row for the database. You can configure a mapping to be read-only or, in the case of a 1:1 mapping, may configure a target foreign key. Both of these will allow an additional mapping of a field.
TopLink supports sequencing by assigning the object a unique identifier when it is inserted into the database. TopLink assigns the identifier here because this is the first time TopLink gets access to the object. When using native sequencing on Sybase, SQL Server and Informix the identifier cannot be obtained until after the insert.
If you want the sequence number assigned at creation time instead of during the insert:
Number nextID = session.getPlatform().getSequenceNumberNamed(" SEQ_NAME",
session, "SESSION_NAME");
Note that this is not a public API protocol, although it is publicly accessible.
Within a unit of work all registered new objects can also be assigned sequence numbers through the assignSequenceNumber(Object)
and assignSequenceNumbers()
methods.
To map a Java inheritance hierarchy in TopLink, each class in the hierarchy will define a TopLink descriptor. Each subclass' descriptor will define its parent to be its superclass.
This inheritance hierarchy can be reflected in the database in many ways. TopLink requires a common table for the root class that must be shared by all of the subclasses. The subclasses are free to define additional tables to store their additional data or can share their parent's tables. TopLink uses an indicator field in the root table to determine the class to instantiate from the row, however this mechanism can be customized if required.
It is a common misconception that a system with a root domain class must be mapped using this kind of inheritance mapping. Typically this should only be done where the database schema dictates or the object model allows similar types to be stored together. If it does not make sense to define a table for the root class, this class can not be mapped at all, or can be mapped as an interface. TopLink supports querying on interface descriptors and does not require that they be mapped to a database table.
In a mapped inheritance hierarchy all subclasses must share the root's primary key. In case of multiple tables the primary key in the additional table may be named differently than in the root table. In this case a name mapping must be provided in the descriptor, or in complex cases a multiple table join expression. The primary key that will be used internally in TopLink and for caching will always be the root table's.
Foreign reference mappings internally use a selection query to read objects from the target. This selection query is like any other read query, and can be accessed to provide advanced customization on the mapping's query. The selection query can itself be changed to provide a custom query if complex querying is required. If you have a relationship that is not solely based on foreign keys, an expression can be given to the mappings selection criteria.
ExpressionBuilder builder = new ExpressionBuilder(); mapping.setSelectionCriteria( builder.getParameter("EMPLOYEE.ADDR_ ID").equal(builder.getField("ADDRESS.ID").and(builder.getField( "ADDRESS.TYPE").equal("home"));
When a source object defines a 1:M mapping to a target object, you must also create a 1:1 mapping from the target object back to the source object in order to populate the foreign key field in the target table. Without this back-mapping, TopLink does not know how to populate this foreign key field in the target table.
You can use an AggregateCollectionMapping
to represent the aggregate (privately-owned) relationship between a single source object and a collection of target objects. Unlike the normal AggregateObjectMapping
, there is a target table being mapped from the target object; unlike the normal 1:M mapping, there is no need for setting the 1:1 back reference, as the foreign key relationships have already been resolved by the aggregation. The AggregateCollectionMapping
was introduced in version 3.0.
You can avoid setting the 1:1 back reference by defining a direct-to-field mapping on the foreign key field. In this case the application must make sure that the object model picks up the correct value from the source object. However, this alternative may result in an overly complex implementation or object model. It is recommended you use a 1:1 back reference.
Another alternative is to define a M:M mapping from source to target and create a relation table. This is the best solution as it ensures that the object model is consistent with the data model. Neither model stores information of the relationship in the target object and multiple source objects referencing the target can be supported.
TopLink supports variable 1:1 mappings in which the source object has a reference to one of two or more non-inherited classes. To define a variable 1:1 mapping the target classes of the mapping must be related through an interface.
You must define an interface descriptor for the interface and the target classes must implement the interface. The selection criteria of the mapping will be defined using query keys from the target interface and a type field in the source object's table will store the type of object that is referenced.
TopLink provides a rich set of type conversions between database types and the Java types provided with JDK. It is possible to make use of additional or third party types in a domain class through customization of TopLink.
TopLink makes use of a singleton ConversionManager
(found in the oracle.toplink.helper
package). Developers can subclass this class and create a custom conversion manager with the additional conversions required. At system startup an instance of this class must be provided as the singleton conversion manager.
By default, TopLink uses the Vector
class for collections. JDK 1.1 supports only Vector
and Hashtable
(or their subclasses). Java 2 can use any implementor of the Collection
or Map
interface. TopLink supports collections through the mapping's container policy. You can define a new container policy that uses other types of containers that do not implement the Collection
or Map
interfaces.
TopLink maps BLOB data from the database into a byte array in the object model. BLOBs can also be mapped through transformation or serialized mappings to be complex objects in the object model.
Because many JDBC drivers have problems dealing with large binary data, TopLink supports multiple options. By default TopLink binds binary data into the SQL statement. TopLink also supports printing the data using the JDBC binary escape clause or native SQL.
Binding is enabled/disabled on the DatabaseLogin
through the dont/useByteArrayBinding()
property. When binding is enabled, TopLink will parameter bind the binary value. Because some JDBC drivers may have problems binding large values (but can support large values through streams), TopLink also supports stream binding. This is enabled in DatabaseLogin
through the useStreamBinding()
property. Some drivers have limits to BLOB sizes that may require your application to split the binary data into multiple fields or use a direct collection or 1:M mapping to map the data.
Large string data may also require binding. TopLink can be configured to bind string data through the useStringBinding(int)
property on DatabaseLogin
.
SerializedObjectMapping
. Mappings of this type will serialize the object structure from the root attribute and store it into a BLOB field on the database. When the object is read from the database it will be de-serialized into its original structure. This mapping does not require the developer to do the serialization, but instead to make sure that objects in the structure are serializable and self contained.
This message is given because SQL is trying to write to a non-existent column in the table. Possible reasons for this could be:
It's likely that, although you have set up the descriptor's and project's sequencing information, that the sequence table is not yet initialized. The sequence table must contain one row for each sequence name you are using, and have an initial value in the count column. For example, if your Employee
and Address
descriptors are using sequencing, an initialized sequence table might look like this:
SEQ_NAME | SEQ_COUNT |
---|---|
EMPLOYEE |
0 |
ADDRESS |
0 |
No. Inheritance in TopLink only needs to be modeled relationally if you plan to query or write the super classes.
Consider the example where class A has a subclass called B. A has two attributes: id
and description
. On the database, there is both an ID and DESCRIPTION field on B's table, but A has no table associated with it. All you need to do is map B; you can ignore its superclass A. The fields contained in A can be mapped through mapping B. This allows you to map an object model but ignore certain classes that shouldn't logically be persisted (e.g. abstract classes, "PersistentObject" superclasses, etc.).
In general, no. You do, however, have to make sure that your attribute is of the correct type. In the case of collection indirection, you must make sure that your attribute type is java.util.Collection. In the case of one-to-one indirection (available only in JDK 1.3), you must make sure that the attribute type is an interface. This is because TopLink replaces the target object with a special wrapper object that implements the same interfaces as the target class. If the variable is not of the correct type, TopLink will not be able to put the value into it.
Serialization can also cause trouble with Transparent Indirection. Unless Remote Sessions are being used, Transparent Indirection can not be instantiated on the client. The same holds true with regular indirection; however, the point at which the indirection is instantiated is now different with Transparent Indirection. Using traditional ValueHolders
, the indirection is triggered as soon as the getAttribute()
method is called. Before an object that is referenced using Transparent Indirection can be accessed on the client, a message must be sent to it on the server (e.g. getSize()
for transparent collections, hashCode()
for transparent one-to-ones, etc.).
TopLink provides two types of sessions for developers to connect with the database:
DatabaseSession
for two-tier applications in which a single JDBC connection will service all database requests.
ServerSession
for three-tier applications. This allows multiple clients to access the database through a configurable JDBC connection pool. TopLink's 3-Tier solution also includes a ClientSession
and a RemoteSession
. Each client to the ServerSession
must communicate through a ClientSession
. The RemoteSession
can be used across RMI, CORBA or EJB from a client applet or application.
DatabaseSession provides the unit of work functionality and much lower level access to the database through insertObject(...)
, updateObject(...)
, deleteObject(...)
, beginTransaction()
, commitTransaction()
, and rollbackTransaction().
These are not provided through the ServerSession
, ClientSession
and RemoteSession
since merging of objects into a shared cache requires the more complicated behavior delivered with TopLink's UnitOfWork.
Each class type has an identity map in a TopLink DatabaseSession or Server Session. Objects are stored in these identity maps based on the object's defined primary key field values.
TopLink guarantees object identity by checking the cache during reads to ensure that for any given set of relational data (which maps to an object) only a single instance of the class is created. This means that multiple reads of the same object will return the same reference. This is extremely valuable in ensuring that object changes made within the application stay in sync with other users of the objects. Object identity also allows the building of complex structures involving circular references without any extra work or potential infinite loop.
Violating object identity refers to creating objects which either already exist in the cache (same class and primary key) or in the database instead of using the object returned from TopLink.
TopLink uses an object's primary key field values, as defined in the descriptor, to identify an object uniquely. The object cache, maintained within either the DatabaseSession
or ServerSession
, caches objects based on class and primary key values. TopLink uses six types of caches which can be configured on a per class basis.
TopLink determines whether to INSERT or UPDATE an object based upon the following existence-checking settings (provided in each persistent class's descriptor):
Use the Check Database option only when caching cannot be guaranteed for modified objects. This option will lower performance (as compared to Check Cache) because it must access the database each time.
In some databases or database configurations table names must be qualified with either a table owner/creator name or a table space name. TopLink allows you to specify these either on a per session basis or individually in each descriptor.
By sending the following method to the DatabaseLogin
object before you login to the session, the table names of all of the registered descriptors will be qualified with the creator or qualifier name.
It is also possible to define individual qualifiers by qualifying the table name in the descriptor using the dot notation. This must be done through an amendment method and is not supported from the TopLink Mapping Workbench.
Some JDBC drivers do not support the JDBC date syntax. In this case TopLink also supports printing date values in their native database syntax. To enable native SQL printing set the useNativeSQL()
property in DatabaseLogin
.
TopLink optimizes the way that data is converted from the JDBC driver. This includes date type where TopLink handles the conversion from strings internally. Some JDBC drivers, when returning the string representation of the date, return the wrong string syntax. In this case you must disable TopLink's data optimization through the dontOptimizeDataConversion()
property in DatabaseLogin
.
TopLink's UnitOfWork provides developers with an object transaction mechanism. TopLink's UnitOfWork provides a working copy of an object and its related objects so that changes can be made in isolation. Upon commit the UnitOfWork identifies what has changed with the registered object's working copies. This minimal change set is then written and committed to the database. Upon successful commit of the changes the modifications are then applied to original copies of the objects.
The UnitOfWork provides the following functionality:
Registration is a process of letting the UnitOfWork maintain and isolate an object's changes. That is why any object you want to change must be registered before you start making changes. The UOW maintains a backup copy of the original object and returns you a working copy to work on. The original object must be left untouched until the UnitOfWork is committed. This ensures that uncommitted changes are not seen by other users of the object.
There are two ways of registering objects in the UnitOfWork:
registerObject()
method. This must be done for objects read outside the UOW. The returned clone from the registerObject()
method must be used for editing.
There is no limit to the number of units of work that can be nested or used in parallel. When a nested unit of work is committed, nothing is changed on the database - instead, the parent unit of work is notified of the changes, and they will be made when the parent is committed. A possible application for nested units of work is a user interface "wizard" in which each page of the wizard could be a separate nested unit of work committed when the user clicks Next. At the last page of the wizard, clicking an OK button commits the parent unit of work, thereby committing all of the nested units of work. Clicking the Cancel button cancels the entire transaction.
Units of work can also be used in parallel. Essentially, this means that multiple units of work can be acquired from a single TopLink Session, and used simultaneously.
Yes, new objects created in the UnitOfWork must be registered but their non-private parts should not be registered as TopLink uses "persistence by reachability" for such objects. This means that if a new object is referenced by another registered object it does not have to be registered. New objects must be registered before they are related to other existing object to ensure the correct clone is referenced by the other object.
This exception is thrown when the unit of work detects that an object referenced from another registered object was never registered.
This can occur when:
toString
to include the object's hashCode
to ensure that you are not confused about which object you are having a problem with.
A ReadAllQuery
and ReadObjectQuery
have the message setEJBQLString(String EJBQLString)
which can be used to set the selection criteria of the query to a String containing EJBQL.
The Mapping Workbench also supports EJBQL queries.
TopLink's rich expression framework allows almost any query to be specified in terms of the object model. These expressions are then dynamically turned into the appropriate SQL at runtime. Features of the expression framework include:
By default reading a parent class will return all the instances of the parent and its subclasses. If only the instances of the parent class are desired, then the inheritance property "should read subclasses" can be turned off on the parent descriptor. If the subclass instances are not desired for a specific query, then the query expression can filter the children. The following gives an example of a subclass filtering expression:
Expression builder = new ExpressionBuilder(); Expression expression = builder.getField("typeIndicatorField").equal("parent");
No, doing this might seem to be working in some cases but would certainly fail in expressions using joins or complex expressions. The recommended way is to always use the same ExpressionBuilder in a single expression.
If your expression contains sub-selects, then the sub-query may have a different ExpressionBuilder, but this should be the only case.
This will happen when using a cache. When objects are read for the first time they are cached into the identity map. When the second read is done the cached objects are returned. This takes less time than constructing objects from the database. The caching is done based upon primary key. If a ReadObjectQuery
is executed with an exact equal clause for all elements of the primary key then it may be possible to get a cache hit and not access the database at all.
Stored procedures are normally accessed through TopLink's custom SQL and stored procedure call support. The stored procedure can be called directly using the session API executeSQL(...)
and executeNonSelectingSQL()
or used in a descriptor's or mapping's custom SQL properties. Stored procedures with output parameters are supported through the StoredProcedureCall
object. Stored procedure calls with output parameters can also be used inside the descriptor's and mapping's properties and executed directly on the session through the DataReadQuery
and DataModifyQuery
objects.
Essentially each time you use anyOf()
in your expression, you will get another join in your database. For example, the TopLink expression:
emp.anyOf("managedEmployees").get("lastName").equal("Smith").and(emp.anyOf("mana gedEmployees").get("firstName").equal("John"));
will return you any Employee who manages a John or a Smith, not only John Smith. This is because a separate join is performed for each anyOf()
. In order to force a single join, the same anyOf
node must be used for each query:
Expression managedEmployees = emp.anyOf("managedEmployees"); ... managedEmployees.get("lastName").equal("Smith").and(managedEmployees.get("firstN ame").equal("John"));
A QueryByExample
does not replace a selection object in a query. A selection object has always been and continues to be an easy mechanism to query by the primary key only. Any other attributes in this object will be ignored. A QueryByExample
object allows you to set up an object with various attributes set to give you better control over your query.
Refer to the Oracle9iAS TopLink Mapping Workbench Reference Guide for detailed information on use the Mapping Workbench.
The TopLink Mapping Workbench is a completely new graphical mapping tool that replaces the TopLink Builder. It is written in Java, and can be used on any platform that supports the Java 2 runtime environment. It uses XML files to store TopLink Project information, and adds new functionality such as optimistic locking, transparent indirection, and enhanced database support. It also uses a multi-document interface, allowing the user to open multiple TopLink Projects simultaneously, and drag-and-drop descriptors and tables between Projects.
The TopLink Mapping Workbench maintains its own CLASSPATH - separate from your system CLASSPATH. To import classes into your Mapping Workbench project, you must first indicate the directories that contain the domain class(es) to map on the project's General tab.
.jar
file, or .zip
file to add.
To add the system's classpath entries to the project, click on Add System Entries.
Unlike the .project
file used by earlier versions of TopLink and TopLink Mapping Workbench, the Mapping Workbench 4.6 .mwp
file cannot be loaded directly into your code to create a TopLink Session. Instead, you must first deploy your Mapping Workbench project as either a single XML file or a Java class.
Select File > Generate Deployment XML from the Mapping Workbench menu to create an XML file. After generating the file, use the following code to load the project into your application:
import oracle.toplink.sessions.Project; import oracle.toplink.tools.workbench.XMLProjectReader; ... Project p = XMLProjectReader.read("C:\\Projects\\Project Name.xml");
Select File > Export to Java Source from the Mapping Workbench menu to create a .java
source file that you can then compile and instantiate in your code.
The TopLink Mapping Workbench uses an XML parser, found in xerces.jar
, to read and write your project information. You may encounter an XML exception if a different XML parser appears first in your system or IDE CLASSPATH before xerces.jar
, this can cause conflicts. Ensure that xerces.jar
is the first XML parser in your CLASSPATH.
Alternatively, use the class loader (included with the TopLink SDK) to use the specific version of Xerces included with TopLink. Refer to the Oracle9iAS TopLink: Foundation Library Guide for more information.
Yes. You can upgrade your previous version Mapping Workbench projects to use with the current version.
TopLink's remote support for CORBA has been upgraded to the latest versions of the industry leading CORBA ORBs. TopLink's remote session and cache synchronization features now support deployment stubs and classes for Borland Inprise Visibroker 4.1, Iona Orbix 2000 and Sun's Java 2 ORB.
It is important to note that the TopLink CMP for BEA WebLogic or TopLink CMP for IBM WebSphere Foundation Libraries are extensions to the TopLink for Java Foundation Library. If your application architecture involves using session beans with regular Java objects, or if you will be implementing Bean-Managed Persistence (BMP) then you can use the standard TopLink for Java Foundation Library. For these kinds or architectures you can use the TopLink for Java Foundation Library with any enterprise Java application server.
The TopLink for Java Foundation Library includes the classes necessary to synchronize with JTS for BEA WebLogic Server, IBM WebSphere Application Server, Oracle8i, and Inprise Application Server. The TopLink CMP for BEA WebLogic and IBM WebSphere Foundation Libraries allow you to use Container-Managed Persistence (CMP) for your entity beans.
Yes, the TopLink SDK allows you to extend TopLink to access objects stored in non-relational data stores. TopLink also comes with an XML extension that allows you to easily read and write your objects from XML files. This extension is used by the TopLink Mapping Workbench to read and write your TopLink Projects.
To take advantage of the SDK you will need to develop a number of classes that can be used by TopLink to access your particular non-relational data store. You will also need to take advantage of a number of new TopLink mappings and use many of the customization hooks provided by TopLink that are not used by a "typical" TopLink application. The new mappings include:
SDKAggregateObjectMapping
SDKAggregateCollectionMapping
SDKDirectCollectionMapping
SDKObjectCollectionMapping
The XML extension is a simple example of how to implement the classes required by the TopLink SDK to access a non-relational data store. By default, the XML extension reads and writes your objects from XML documents located in native files. But it is flexible enough that you can plug in your own classes that get the XML documents from elsewhere (e.g. a messaging service, a URL). There are numerous other areas where you can plug in your own classes to modify the behavior of either the SDK or the XML extension.
|
Copyright © 2002 Oracle Corporation. All Rights Reserved. |
|