DN v5 : Improved support for Enum persistence

With standard JDO and JPA you can persist a Java enum field as either the name (String-based column) or the ordinal (Number-based column). This is great as far as it goes, so we can easily persist fields using this enum.

public enum Colour{RED, GREEN, BLUE;}

In some situations however you want to configure what is stored. Say, we want to store a numeric value for each enum constant but not the default values (for some reason). In DataNucleus up to and including v4 (for RDBMS only!) we allowed persistence of

public enum Colour
{
    RED(1), 
    GREEN(3), 
    BLUE(5);

    int code;
    private Colour(short val) {this.code = val;}
    public short getCode() {return this.code;}
    public static Colour getEnumByCode(short val)
    {
        case 1: return RED;
        case 3: return GREEN;
        case 5: return BLUE;
    }
}

and then you set metadata for each enum field of this type to specify that you want to persist the “code” value, like this

@Extensions({
    @Extension(vendorName="datanucleus", key="enum-getter-by-value", value="getEnumByCode"),
    @Extension(vendorName="datanucleus", key="enum-value-getter", value="getCode")
   })
Colour colour;

This was fine, except required too much of the user.

 

DataNucleus v5 simplifies it, and you can now do

public enum Colour
{
    RED(1), 
    GREEN(3), 
    BLUE(5);

    int code;
    private Colour(short val) {this.code = val;}
    public short getCode() {return this.code;}
}

and mark each enum field like this

@Extension(vendorName="datanucleus", key="enum-value-getter", value="getCode")
Colour colour;

We don’t stop there however, because the value that is persisted using this extended method can now be either short, int or String. It is also now available for use on RDBMS, Cassandra, MongoDB, HBase, Neo4j, ODF, Excel, and JSON, so your code is more portable too!

Posted in Uncategorized | Leave a comment

DN v5 : Support for Java8 “Optional”

Java 8 introduces a class (java.util.Optional) that represents either a value or null. DataNucleus v5 has a requirement of Java 8, and adds support for persisting and querying fields of this type. Let’s suppose we have a class like this

public class MyClass
{
    private Optional<String> description;
    ...
}

By default DataNucleus will persist this as if it was of the generic type of the Optional (String in this example). Consequently on an RDBMS we will have a column in the datastore of type VARCHAR(255) NULL. If the field description represents a null then it will be persisted as NULL, otherwise as the value contained in the Optional. It supports the generic type being a normal basic type (though not a collection, map, array), or a persistable object.

JDOQL in JDO 3.2 adds support for querying the Optional field, like this

Query q = pm.newQuery(
    "SELECT FROM mydomain.MyClass WHERE description.isPresent()");

So this will return all instances of the class where the description field represents a value. Similarly we can return the value represented by the Optional field, like this

Query q = pm.newQuery(
    "SELECT description.get() FROM mydomain.MyClass");

As you can see, JDOQL makes use of standard Java method namings for accessing the Optional field.

For JPA querying, you can simply refer to the Optional field as if it was of the generic type represented.

This is part of the JDO3.2 spec and you can make use of it in DataNucleus v5+. It is not currently part of the JPA2.1 spec, but you still can make use of it in DataNucleus v5+ when using JPA.

Posted in Uncategorized | Leave a comment

DN v5 : JPA with “nondurable” identity

With standard JPA you only have the ability to have “application” identity for an entity (i.e field(s) marked as being part of the primary-key). Some time ago we added vendor extension support for having a surrogate (datastore) identity for an entity with DataNucleus. DataNucleus v5 now adds a further vendor extension whereby you can have an entity that has no identity. This is useful where you maybe have a class that represents a log entry and you don’t have need to access a specific object (other than searching for all entries with particular field value(s)). You would do this as follows

@Entity
@org.datanucleus.api.jpa.annotations.NonDurableId
public class LogEntry
{
    String level;
    String category;
    String message;

    ...
}

Note that you can specify this in orm.xml also, see the DataNucleus documentation. So we have made use of a DataNucleus-specific annotation, and now we can persist objects of this type and they will not be assigned an identity. We now handle objects of this type in the normal way for querying, just that we cannot use em.find(…).

This is not part of the JPA 2.1 spec, and is not likely to be included in a JPA spec any time soon, but you can make use of it in DataNucleus v5+.

Posted in Uncategorized | Leave a comment

DN v5 : JPQL FROM JOIN to another “root” entity

A vendor extension now available in DataNucleus v5 is for JPQL’s ability to JOIN to other entities. In standard JPQL you can only add a JOIN through a relation. For example

SELECT p FROM Person p 
    JOIN p.address a WHERE a.street = 'Main Street'

In this example we have a candidate “root” entity of Person, and are joining to the Address entity via the “address” relation field in Person.

The vendor extension provides the ability to join to a new “root” entity. For example

SELECT p FROM Person p 
    LEFT OUTER JOIN Address a ON p.addressName = a.name

In this example we have a candidate “root” entity of Person, and we are joining to the Address entity using a manually specified ON clause. That is, there doesn’t need to be a relation between Person and Address to make this join, just a condition that we are imposing in the ON clause.

This is not part of the JPA 2.1 spec, but may be in a future JPA spec, but you can make use of it in DataNucleus v5+.

Posted in Uncategorized | Leave a comment

JDO 3.2 JDOQLTypedQuery : improvements relative to DN extension

Now that JDO 3.2 standardises the “typed query” mechanism that we prototyped in DataNucleus v3.x and v4.0/v4.1 it is worth mentioning the additions to the API that are present in the JDO 3.2 variant.

StringExpression

This has gained the following methods to providing JDOQL “matches” operation capability

BooleanExpression matches(StringExpression expr);
BooleanExpression matches(String str);

 

NumericExpression

The following methods are added, for bitwise operations support

NumericExpression bAnd(NumericExpression bitExpr);
NumericExpression bOr(NumericExpression bitExpr);
NumericExpression bXor(NumericExpression bitExpr);

In addition it also gains these methods to match the equivalent JDOQL string based operators (-, ~)

NumericExpression neg();
NumericExpression com();

 

CharacterExpression

This also gains the JDOQL string based operators (-, ~)

NumericExpression neg();
NumericExpression com();

 

BooleanExpression

This gains the JDOQL string based operator (-)

BooleanExpression neg();

Java 8

In addition to the above you can now also make use of Java8 Time types in JDOQLTypedQuery, whereas this was not possible in the previous DataNucleus extension.

 

API

The JDOQLTypedQuery class has some slight changes to make it more consistent with the JDOQL standard API.

  • Added method result(…) rather than specifying result clauses in the execute call.
  • Changed addExtension/setExtensions methods to extension(…)/extensions(…).
  • Added unmodifiable, serializeRead, datastoreReadTimeout, datastoreWriteTimeout, ignoreCache, saveAsNamedQuery.
Posted in JDO, JDOQL, LINQ, Uncategorized | Leave a comment

JDO 3.2 JDOQLTypedQuery

JDO 3.2 is now standardising what we initially developed as a DataNucleus extension for JDO querying, namely typesafe queries. In DataNucleus upto and including v4.1 it was referred to as JDOQL Typesafe Query, and in JDO 3.2 (DataNucleus v4.2+) it is called JDOQLTypedQuery. Here we present some examples, the same examples as a previous blog post about the original DataNucleus extension but now updated to the JDOQLTypedQuery API.

In these examples we have a class Product. Consequently we have a “query” class autogenerated – QProduct. Here is the QProduct class

public class QProduct extends PersistableExpressionImpl implements PersistableExpression
{
    public static QProduct candidate() {...} // candidate "this"
    public static QProduct candidate(String name) {...}
    public static QProduct parameter(String name) {...}
    public static QProduct variable(String name) {...}
    public NumericExpression id;
    public StringExpression name;
    public NumericExpression value;
    ...
}

So, as you can see we have access to the persistable fields/properties of Product by way of public fields in its query class. Now on to some examples

Filter only
Here we select all Products that have a value less than 40.0

JDOQLTypedQuery tq = pm.newJDOQLTypedQuery(Product.class);
List<Product> results = tq.filter(QProduct.candidate().value.lt(40.0))
    .executeList();

Filter + Order
Here we select all Products that have a value less than 40.0 and ordering by their name

JDOQLTypedQuery tq = pm.newJDOQLTypedQuery(Product.class);
QProduct cand = QProduct.candidate();
List<Product> results = tq.filter(cand.value.lt(40.0))
    .orderBy(cand.name.asc())
    .executeList();

Filter + Order + Result
Here we select the product name and product value for all Products that have a value less than 40.0 , ordering by their name

JDOQLTypedQuery tq = pm.newJDOQLTypedQuery(Product.class);
QProduct cand = QProduct.candidate();
List results = tq.filter(cand.value.lt(40.0)).orderBy(cand.name.asc())
    .result(true, cand.name, cand.value)
    .executeResultList();

Filter with Methods
Here we select all Products that have a value less than 40.0 and name starting with “Wal”, and ordering by their name

JDOQLTypedQuery tq = pm.newJDOQLTypedQuery(Product.class);
QProduct cand = QProduct.candidate();
List<Product> results = 
    tq.filter(cand.value.lt(40.0).and(cand.name.startsWith("Wal")))
    .executeList();

Filter, using Parameters
Here we select all Products that have a value less than 40.0, using a parameter

JDOQLTypedQuery tq = pm.newJDOQLTypedQuery(Product.class);
QProduct cand = QProduct.candidate()
List<Product> results = 
    tq.filter(cand.value.lt(tq.doubleParameter("param1")))
    .setParameter("param1", 40.0)
    .executeList();

Order + Range
Here we select Products, ordering by the name and restrict to the first two

JDOQLTypedQuery tq = pm.newJDOQLTypedQuery(Product.class);
QProduct cand = QProduct.candidate();
List<Product> results = tq.orderBy(cand.name.asc()).range(0,2)
    .executeList();

Filter with Variable
Here we select Inventory (which has a collection of Products) that contain a Product with a particular name

JDOQLTypedQuery tq = pm.newJDOQLTypedQuery(Inventory.class);
QInventory cand = QInventory.candidate();
QProduct var = QProduct.variable("var");
List<Product> results = 
    tq.filter(cand.products.contains(var).and(var.name.startsWith("Wal")))
    .executeList();

Filter with Subquery
Here we select Products with a value less than the average value of any Product

JDOQLtypedQuery tq = pm.newJDOQLTypedQuery(Product.class);
QProduct cand = QProduct.candidate();
JDOQLTypedSubquery tqsub = tq.subquery(Product.class, "p");
QProduct candsub = QProduct.candidate("p");
List<Product> results = 
    tq.filter(cand.value.lt(tqsub.select(candsub.value.avg())))
    .executeList();

As you can see from the above queries we have no hard-coded class or field names, providing better refactorability. We can obviously make use of all JDOQL supported methods in the above queries, and define parameters and variables just like in the standard (string-based) JDOQL API.

It should be noted that this JDOQL facility is much more elegant and requires less code than the equivalent queries using JPA “Criteria”.

Posted in Criteria, DataNucleus, JDO, JDOQL, JPA, JPQL, Typesafe | Leave a comment

JDO 3.2 Revisions to Query API

Here we present some changes to the JDO Query API that are coming in version 3.2 of the spec. Comments should be directed ASAP to the Apache JDO mailing list if you want any changes to make it in to this next revision.

Fluent API
When you are specifying a JDOQL query using the assorted setter methods you can end up with code like this

Query q = pm.newQuery(Manager.class);
q.setFilter("theDepts.contains(dept0) && dept0.manager == this");
q.declareParameters("mydomain.model.Department[] theDepts");
q.declareVariables("mydomain.model.Department dept0");
q.setOrdering("this.firstName ascending");

Clearly this leaves a lot to be desired in terms of API. In JDO 3.2 you can now do the following

Query q = pm.newQuery(Manager.class)
    .filter("theDepts.contains(dept0) && dept0.manager == this")
    .parameters("mydomain.model.Department[] theDepts")
    .variables("mydomain.model.Department dept0")
    .ordering("this.firstName ascending")
    .setParameters(depts);

So you can chain your specification(s). The other thing of note is that you can now set the parameter values prior to execution. The reason for this comes next.

No casting on execute()
With the former query above, we would execute it as follows

Collection<Manager> managers = (Collection<Manager>) q.execute(depts);

With JDO 3.2 we can execute it like this

Collection<Manager> managers = q.executeList();

I think we can conclude that this is much cleaner. There is no need to cast the result from the execute method, simply using a different execute method based on what your query is expected to return.

Save as a NamedQuery
You can now construct a query, and save it as a named query, so you don’t need to regenerate it. You do that as follows

Query q = pm.newQuery("SELECT FROM Person WHERE this.lastName == :surname");
q.saveAsNamedQuery("FindPeopleWithSurname");

So from that point forwards when you need that query, you can do the following

Query q = pm.newNamedQuery(Person.class, "FindPeopleWithSurname");
Posted in Uncategorized | Leave a comment