Skip Headers

Oracle TopLink Developer's Guide 10g Release 3 (10.1.3) B13593-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# Using Conforming Queries and Descriptors

Because queries are executed on the database, querying though a unit of work will not, by default, include new, uncommitted objects in a unit of work. The unit of work will not spend time executing your query against new, uncommitted objects in the unit of work unless you explicitly tell it to. If you have uncommitted changes, this can pose a problem in a unit of work. Uncommitted changes not yet written to the database cannot influence which result set gets returned.

Conforming is a query feature that lets you include new, changed, or deleted objects in queries within a unit of work prior to committing. This lets you to query against your relative logical or transaction view of the database.

Before you use conforming, be aware of its limitations (see "Guidelines for Using Conforming") and make sure that conforming is actually necessary. For example, consider the alternative described in "Conforming Query Alternatives".

This section explains the following:

- Guidelines for Using Conforming

- Using Conforming Queries

- Using Conforming Descriptors

- Conforming Query Alternatives

Note: By default, TopLink suppresses exceptions thrown during the memory search stage of conforming. For more information on handling exceptions during conforming, see "Exceptions During Conforming".

## Guidelines for Using Conforming

When using conforming, follow the guidelines that this section describes to ensure that conforming queries return results:

- Use Only In-Memory Queries that Support Conforming

- Consider How Conforming Affects Database Results

- If You Want an Object in the Conformed Results, Register it in the Unit of Work

### Use Only In-Memory Queries that Support Conforming

Conforming is supported by the following in-memory queries:

- `ReadObjectQuery`

- `ReadAllQuery`

- Query by example (`ReadAllQuery` only)

- Query by selection object or primary key (only new or deleted objects apply)

Conforming is not supported by any other type of in-memory query.

For more information, see "Using In-Memory Queries".

### Consider How Conforming Affects Database Results

Table 102-1 summarizes conforming behavior for in-memory queries.

Table 102-1 Conforming Support for In-Memory Queries

Query Type | Conforming's Effect on Database Result
--- | ---
In-memory query without joining | Considers both explicitly and implicitly created (new), changed, or deleted objects in the unit of work: Removes explicitly or implicitly deleted objects Adds explicitly or implicitly created objects Adds explicitly or implicitly changed objects
In-memory query with joining | Considers only explicitly created, changed, or deleted objects in the unit of work: Removes explicitly deleted objects Adds explicitly created objects Adds explicitly changed objects
Unsupported in-memory queries | Removes explicitly deleted objects

Note: If a `ReadObjectQuery` returns a single result from the database and if that object is deleted in the unit of work, nothing is returned.

### If You Want an Object in the Conformed Results, Register it in the Unit of Work

Consider the example shown in Figure 102-1. In this example, you have `Employee` objects with an `address` attribute configured for indirection (see "Indirection") mapped by a one-to-one mapping to an `Address` object.

Figure 102-1 Conforming Example

Description of "Figure 102-1 Conforming Example"

You want to read all employees who live in Ottawa but first, you need to modify some of the `Address` objects to change city from Toronto to Ottawa. Jane Doe is one such employee.

First, using the `UnitOfWork`, you read all `Address` objects and change some `city` attributes (including Jane's) from Toronto to Ottawa. Then you run a conforming query to get all employees who live in Ottawa. However, Jane is not included in the results, even though she now lives in Ottawa:

- Jane is not returned from the database because the transaction has not yet been committed and in the database, her address still says Toronto.

- Jane cannot be added to the conformed result in memory because she is not registered in the `UnitOfWork` cache.

Conforming only recognizes explicit changes. In this example, Jane Doe's `Employee` object was only implicitly changed. In order to be considered explicitly changed, an `Employee` must:

- be registered in the `UnitOfWork`

- have its `address` attribute changed (in this example, indirection must be triggered for the `address` attribute)

The correct way to handle this example would be as follows:

1. Using the `UnitOfWork`, read in all employees with addresses outside of Ottawa.

   All these `Employee` objects are now registered with the `UnitOfWork`

2. Using the same `UnitOfWork`, read in all addresses outside of Ottawa.

   All these `Address` objects are registered with the `UnitOfWork`.

3. Modify the addresses, changing some of the addresses to be in Ottawa.

4. Run the conforming query on employees with addresses inside Ottawa.

   The conforming query triggers indirection.

   All employees with addresses in Ottawa are returned, including both employees that were in Ottawa originally and employees whose addresses were changed in this transaction.

5. Commit the transaction.

Note that even if the conforming query triggers indirection, in this example, there may be no extra database reads because of the one-to-one mapping and the fact that the Address objects are in the cache. If you do not register all employees whose address may be changed, the conforming query will not include Jane.

An alternate approach is to use short transactions: the safest conforming query is one made immediately after a commit. For example:

1. Using the `UnitOfWork`, read in all addresses outside of Ottawa.

2. Modify the addresses, changing some of the addresses to be in Ottawa

3. Commit the transaction.

4. Using the `UnitOfWork`, read in all employees inside Ottawa.

## Using Conforming Queries

Assume that a single `Pet` of type `Cat` already exists on the database. Examine the code shown in Example 102-6.

Example 102-6 Using Conforming Queries

    UnitOfWork uow = session.acquireUnitOfWork();
        Pet pet2 = new Pet();
        Pet petClone = (Pet)uow.registerObject(pet2);
        petClone.setId(200);
        petClone.setType("Cat");
        petClone.setName("Mouser");

        ReadAllQuery readAllCats = new ReadAllQuery();
        readAllCats.setReferenceClass(Pet.class);
        ExpressionBuilder builder = new ExpressionBuilder();
        Expression catExp = builder.get("type").equal("Cat");
        readAllCats.setSelectionCriteria(catExp);

        Vector allCats = (Vector)uow.executeQuery(readAllCats);

        System.out.println("All 'Cats' read through UOW are: " + allCats);
    uow.commit();

This produces the following output:

    All 'Cats' read through UOW are: [Pet type Cat named Fluffy id:100]

If you tell the query `readAllCats` to include new objects:

    readAllCats.conformResultsInUnitOfWork();

The output would be:

    All 'Cats' read through UOW are: [Pet type Cat named Fluffy id:100, Pet type Cat named Mouser id:200]

## Using Conforming Descriptors

TopLink's support for conforming queries in the unit of work can be specified at the descriptor level.

You can define a descriptor directly to always conform results in the unit of work so that all queries performed on this descriptor conform its results in the unit of work by default. You can specify this either within code or from the TopLink.

You can configure a descriptor to always conform in the unit of work using the TopLink or Java code.

To configure a descriptor to always conform in the unit of work in Java code, use `Descriptor` method `setShouldAlwaysConformResultsInUnitOfWork`, passing in an argument of `true`.

To configure a descriptor to always conform in the unit of work using TopLink, see "Configuring Unit of Work Conforming at the Descriptor Level".

## Conforming Query Alternatives

This section describes alternatives to conforming that may meet your needs without the performance penalty imposed by conforming. This section describes the following:

- Using Unit of Work Method writeChanges Instead of Conforming

- Using Unit of Work Properties Instead of Conforming

### Using Unit of Work Method writeChanges Instead of Conforming

Using `UnitOfWork` method `writeChanges`, you can write uncommitted changes to the data source: you can execute report queries, noncaching queries, and data read and modify queries against these changes (see Example 102-7).

Example 102-7 Using Unit of Work Method writeChanges

    UnitOfWork uow = session.acquireUnitOfWork();
        Pet pet = new Pet();
        Pet petClone = (Pet)uow.registerObject(pet);
        petClone.setId(100);
        petClone.setName("Fluffy");
        petClone.setType("Cat");

    uow.writeChanges();

    // Use uow to perform report, noncaching, and data read and modify queries
    // against the changes made so far

    uow.commit();

However, you can call `writeChanges` only once; any attempt to register objects or to execute object-level queries will throw an exception.

For more information, see "Writing Changes Before Commit Time"

### Using Unit of Work Properties Instead of Conforming

Sometimes, you need to provide other code modules with access to new objects created in a unit of work. Conforming can be used to provide this access. However, the following alternative is significantly more efficient.

Somewhere a unit of work is acquired from a session and is passed to multiple modules for portions of the requisite processing:

    UnitOfWork uow = session.acquireUnitOfWork();

In the module that creates the new employee, note the following:

    Pet newPet = new Pet();
    Pet newPetClone = (Pet)uow.registerObject(newPet);
    uow.setProperty("NEW PET", newPet);

In other modules where `newPet` needs to be accessed for further modification, it can simply be extracted from the unit of work's properties:

    Pet newPet = (Pet) uow.getProperty("NEW PET");
    newPet.setType("Dog");

Conforming queries are ideal if you are not sure if an object has been created yet or the criteria is dynamic.

However, for situations where the quantity of objects is finite and well known, using unit of work properties is a simple and more efficient solution.