JDO Typesafe Refactorable Queries

One of the primary drawbacks with current JDO queries is that they are string-based, so you are hardcoding field names etc. When you refactor a (model) class, the field names are left unchanged, so the query no longer works. Some efforts have been made to simplify this process by providing a form of type-safe query (called "criteria" queries by some, but the name is misleading since all queries define criteria) - see JPA2 Criteria queries, and also QueryDSL. Of the current offerings the QueryDSL fluent API approach is considered by many to be the most elegant.

JDO needs such a type-safe refactorable query API. However it is important that this does not go down the track followed by JPA Criteria queries (IMHO) since it leads to excessive code just to generate a query, hence the fluent approach make more sense. What we are proposing would be something similar to the following (taken from QueryDSL, but adapted to use more JDOQL-like syntax)

QCustomer customer = QCustomer.customer;
Query<Customer> q = pm.newTypesafeQuery(customer);
Customer bob = q.filter(customer.firstName.eq("Bob"))
.unique(true).execute();


where the QCustomer class is generated automatically (during compilation via an annotation processor, or optionally via a separate process when not using JDO annotations).

The idea is to provide support for all JDOQL syntax via this API, yet provide type-safe handling and refactorability, introducing this in the DataNucleus AccessPlatform 2.2 timeframe, and finally to standardise something similar into JDO 3.1. Your ideas/comments are welcome.

Persisting multisets (bags) with DataNucleus

A multiset is a set where you can have a particular object multiple times in the set (a normal java.util Set will remove dups). This is also known by some as a "bag". Google's Collections library has such a container class (Multiset), and fields of this type are now persistable using DataNucleus.

  • Put the datanucleus-googlecollections plugin in the CLASSPATH

  • Develop your model using the Multiset java type.

  • Make sure that your Multiset field uses a join-table when persisting to RDBMS, and that the join-table doesn't have a primary-key defined


So if we have

@PersistenceCapable
public class Sample
{
@Join(extensions=
@Extension(vendorName="datanucleus",
key="primary-key", value="false"))
Multiset elements = null;
...
}

this will create an RDBMS join table as

CREATE TABLE SAMPLE_ELEMENTS
(
ID_OID BIGINT NOT NULL,
ID_EID BIGINT NOT NULL
);

i.e no primary key, and so we can have duplicates of the same element in the Multiset.
Thereafter the persistence just performs as normal (for JDO or JPA).