JdoSupportService

Primarily provides access to the current thread’s PersistenceManagerFactory and hence also the current thread’s PersistenceManager .

API

JdoSupportService.java
interface JdoSupportService {
  PersistenceManagerFactory getPersistenceManagerFactory()
  T refresh(T domainObject)     (1)
  void ensureLoaded(Collection<?> collectionOfDomainObjects)
  List<Map<String, Object>> executeSql(String sql)
  Integer executeUpdate(String sql)
  void deleteAll(Class<?>... pcClasses)     (2)
  List<T> executeQuery(Class<T> cls, BooleanExpression filter)     (3)
  List<T> executeQuery(Class<T> cls)
  T executeQueryUnique(Class<T> cls, BooleanExpression filter)     (4)
  T executeQueryUnique(Class<T> cls)
  JDOQLTypedQuery<T> newTypesafeQuery(Class<T> cls)     (5)
  void disableMultivaluedFetch(JDOQLTypedQuery<?> query)     (6)
  void disableMultivaluedFetch(Query<?> query)     (7)
  PersistenceManager getPersistenceManager()
}
1 refresh(T)

Force a reload (corresponding to the JDO PersistenceManager 's refresh() method) of a domain objects.

2 deleteAll(Class)

Force the deletion of all instances of the specified class.

3 executeQuery(Class, BooleanExpression)

To perform the most common use-case of executing a (type-safe) query against the specified class, filtering using the provided BooleanExpression , then automatically cloning the returned list and closing the query.

4 executeQueryUnique(Class, BooleanExpression)

To perform a common use-case of executing a (type-safe) query against the specified class, filtering a unique match using the provided BooleanExpression , then returning the result and closing the query.

5 newTypesafeQuery(Class)

To support the execution of type-safe queries using DataNucleus' lower-level APIs (eg for group by and so on).

6 disableMultivaluedFetch(JDOQLTypedQuery)

Fetch Optimization

7 disableMultivaluedFetch(Query)

Fetch Optimization

Members

refresh(T)

Force a reload (corresponding to the JDO PersistenceManager 's refresh() method) of a domain objects.

In fact, this may just reset the lazy-load state of the domain object, but the effect is the same: to cause the object’s state to be reloaded from the database.

The particular example that led to this method being added was a 1:m bidirectional relationship, analogous to Customer <→ * Order . Persisting the child Order object did not cause the parent Customer 's collection of orders to be updated. In fact, JDO does not make any such guarantee to do so. Options are therefore either to maintain the collection in code, or to refresh the parent.

deleteAll(Class)

Force the deletion of all instances of the specified class.

Note: this is intended primarily for testing purposes, eg clearing existing data as part of installing fixtures. It will generate a SQL DELETE for each instance. To perform a bulk deletion with a single SQL DELETE , use #executeUpdate(String) .

Implementation note: It can occasionally be the case that Causeway' internal adapter for the domain object is still in memory. JDO/DataNucleus seems to bump up the version of the object prior to its deletion, which under normal circumstances would cause Causeway to throw a concurrency exception. Therefore To prevent this from happening (ie to force the deletion of all instances), concurrency checking is temporarily disabled while this method is performed.

executeQuery(Class, BooleanExpression)

To perform the most common use-case of executing a (type-safe) query against the specified class, filtering using the provided BooleanExpression , then automatically cloning the returned list and closing the query.

Typical usage:

         final QToDoItem q = QToDoItem.candidate();
         return executeQuery(ToDoItem.class,
                             q.atPath.eq(atPath).and(
                             q.description.indexOf(description).gt(0))
                             );

executeQueryUnique(Class, BooleanExpression)

To perform a common use-case of executing a (type-safe) query against the specified class, filtering a unique match using the provided BooleanExpression , then returning the result and closing the query.

Typical usage:

         final QToDoItem q = QToDoItem.candidate();
         return executeQueryUnique(ToDoItem.class,
                             q.atPath.eq(atPath).and(
                             q.description.eq(description))
                             );

newTypesafeQuery(Class)

To support the execution of type-safe queries using DataNucleus' lower-level APIs (eg for group by and so on).

Responsibility for cloning any result sets and closing the query is the responsibility of the caller.

disableMultivaluedFetch(JDOQLTypedQuery)

Fetch Optimization

FromDN-5.2…​

For RDBMS any single-valued member will be fetched in the original SQL query, but with multiple-valued members this is not supported. However what will happen is that any collection/array field will be retrieved in a single SQL query for all candidate objects (by default using an EXISTS subquery); this avoids the "N+1" problem, resulting in 1 original SQL query plus 1 SQL query per collection member. Note that you can disable this by either not putting multi-valued fields in the FetchPlan, or by setting the query extension datanucleus.rdbms.query.multivaluedFetch to none (default is "exists" using the single SQL per field).

disableMultivaluedFetch(Query)

Fetch Optimization

Examples and Usage

The JdoSupportService service provides a number of general purpose methods for working with the JDO/DataNucleus objectstore. In general these act at a lower-level of abstraction than the APIs normally used (specifically, those of RepositoryService), but nevertheless deal with some of the most common use cases. For service also provides access to the underlying JDO PersistenceManager for full control.

The following sections discuss the functionality provided by the service, broken out into categories.

Executing SQL

You can use the JdoSupportService to perform arbitrary SQL SELECTs or UPDATEs:

public interface JdoSupportService {
    @Programmatic
    List<Map<String, Object>> executeSql(String sql);
    @Programmatic
    Integer executeUpdate(String sql);
    ...
}

The executeSql(…​) method allows arbitrary SQL SELECT queries to be submitted:

List<Map<String, Object>> results = jdoSupportService.executeSql("select * from custMgmt.customers");

The result set is automatically converted into a list of maps, where the map key is the column name.

In a similar manner, the executeUpdate(…​) allows arbitrary SQL UPDATEs to be performed.

int count = jdoSupportService.executeUpdate("select count(*) from custMgmt.customers);

The returned value is the number of rows updated.

As an alternative, consider using DataNucleus' type-safe JDO query API, discussed below.

Type-safe JDOQL Queries

DataNucleus provides an extension to JDO, so that JDOQL queries can be built up and executed using a set of type-safe classes.

The types in question for type safe queries are not the domain entities, but rather are companion "Q…​" query classes. These classes are generated dynamically by an annotation processor as a side-effect of compilation, one "Q…​" class for each of the @PersistenceCapable domain entity in your application. For example, a ToDoItem domain entity will give rise to a QToDoItem query class. These "Q…​" classes mirror the structure of domain entity, but expose properties that allow predicates to be built up for querying instances, as well as other functions in support of order by, group by and other clauses.

The IntelliJ IDE automatically enables annotation processing by default, as does Maven. Using Eclipse IDE you may need to configure annotation processing manually; see the Setup Guide. The DataNucleus' documentation offers some guidance on confirming that APT is enabled.

The JdoSupportService service offers two methods at different levels of abstraction:

public interface JdoSupportService {
    <T> List<T> executeQuery(final Class<T> cls, final BooleanExpression be);
    <T> T executeQueryUnique(final Class<T> cls, final BooleanExpression be);
    <T> TypesafeQuery<T> newTypesafeQuery(Class<T> cls);
    ...
}

The executeQuery(…​) method supports the common case of obtaining a set of objects that meet some criteria, filtered using the provided BooleanExpression. To avoid memory leaks, the returned list is cloned and the underlying query closed.

For example, consider an implementation of ToDoItemRepository using type-safe queries. The following JDOQL:

SELECT
FROM todoapp.dom.module.todoitem.ToDoItem
WHERE atPath.indexOf(:atPath) == 0
   && complete == :complete")

can be expressed using type-safe queries as follows:

public List<ToDoItem> findByAtPathAndCategory(final String atPath, final Category category) {
    final QToDoItem q = QToDoItem.candidate();
    return jdoSupportService.executeQuery(ToDoItem.class,
            q.atPath.eq(atPath).and(
            q.category.eq(category)));
}

You can find the full example of the JDOQL equivalent in the RepositoryService

The executeUniqueQuery(…​) method is similar to executeQuery(…​), however expects the query to return at most a single object, which it returns (or null if none).

The newTypesafeQuery(…​) method is a lower-level API that allows a type safe query to be instantiated for most sophisticated querying, eg using group by or order by clauses. See the DataNucleus documentation for full details of using this.

One thing to be aware of is that after the query has been executed, it should be closed, using query.closeAll(). If calling query.executeList() we also recommend cloning the resultant list first. The following utility method does both of these tasks:

private static <T> List<T> executeListAndClose(final TypesafeQuery<T> query) {
    final List<T> elements = query.executeList();
    final List<T> list = Lists.newArrayList(elements);
    query.closeAll();
    return list;
}

Fixture support

When writing integration tests you’ll usually need to tear down some/all mutable transactional data before each test. One way to do that is to use the executeUpdate(…​) method described above.

Alternatively, the deleteAll(…​) method will let your test delete all instances of a class without resorting to SQL:

public interface JdoSupportService {
    void deleteAll(Class<?>... pcClasses);
    ...
}

For example:

public class TearDownAll extends FixtureScriptAbstract {
    @Override
    protected void execute(final ExecutionContext ec) {
        jdoSupportService.deleteAll(Order.class);
        jdoSupportService.deleteAll(CustomerAddress.class);
        jdoSupportService.deleteAll(Customer.class);
    }
    @Inject
    JdoSupportService jdoSupportService;
}

It can occasionally be the case that Apache Causeway' internal adapter for the domain object is still in memory. JDO/DataNucleus seems to bump up the version of the object prior to its deletion, which under normal circumstances would cause Apache Causeway to throw a concurrency exception. Therefore to prevent this from happening (ie to force the deletion of all instances), concurrency checking is temporarily disabled while this method is performed.

Reloading entities

An (intentional) limitation of JDO/DataNucleus is that persisting a child entity (in a 1:n bidirectional relationship) does not cause the parent’s collection to be updated.

public interface JdoSupportService {
    <T> T refresh(T domainObject);
    void ensureLoaded(Collection<?> collectionOfDomainObjects);
    ...
}

The refresh(T domainObject) method can be used to reload the parent object (or indeed any object). Under the covers it uses the JDO PersistenceManager#refresh(…​) API.

The ensureLoaded(…​) method allows a collection of domain objects to be loaded from the database in a single hit. This can be valuable as a performance optimization to avoid multiple roundtrips to the database. Under the covers it uses the PersistenceManager#retrieveAll(…​) API.

JDO PersistenceManager

The functionality provided by JdoSupportService focus only on the most common use cases. If you require more flexibility than this, eg for dynamically constructed queries, then you can use the service to access the underlying JDO PersistenceManager API:

public interface JdoSupportService {
    PersistenceManager getJdoPersistenceManager();
    ...
}

For example:

public class Orders {

    public List<Order> findOrders( /* ... */ ) {
        javax.jdo.PersistenceManager pm = jdoSupportService.getPersistenceManager();

        ...

        return someListOfOrders;
    }

    @Inject
    JdoSupportService jdoSupportService;
}