Reputation: 18751
I'm creating a Java web app in Google App Engine with JDO.
I have a class User that has an attribute SessionToken. Both classes are persistent with an owned one-to-one relationship.
@PersistenceCapable
public class User {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
@Persistent
private SessionToken sessionToken;
//getters and setters...
}
@PersistenceCapable
public class SessionToken {
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
@Persistent
private String token;
//getters and setters...
}
Now I'd like to have a method to get an user from the Datastore using the attribute token of the SessionToken. I mean, I'd need something like this:
Query query = pm.newQuery(User.class);
query.setFilter("sessionToken.token == tokenParam");
query.declareParameters("String tokenParam");
//return retrieved user if any...
But this isn't working because the query can't access to the attributes in the child object.
It throws this exception:
javax.jdo.JDOFatalUserException: SELECT FROM com.mockgaeapp.User
WHERE sessionToken.token == tokenParam PARAMETERS String tokenParam:
Can only reference properties of a sub-object if the sub-object is embedded.
The only way I can do it is getting first the SessionToken and then the correspondent User, something like:
//First retrieve the SessionToken...
Query query = pm.newQuery(SessionToken.class);
query.setFilter("token == tokenParam");
query.declareParameters("String tokenParam");
List<SessionToken> tokens = (List<SessionToken>) query.execute(sessionToken);
if (!tokens.isEmpty()) {
//... then retrieve the User
query = pm.newQuery(User.class);
query.setFilter("sessionToken == sessionTokenParam");
query.declareParameters("String sessionTokenParam");
List<User> users = (List<User>) query.execute(tokens.get(0));
//return retireved user if any...
}
I was wondering if there's other way to do it, using only one query, or even if there's some way else... Moreover we have to take into account that this operation will be performed many times...
EDIT: I've found a simpler way that is also working. Once I have retrieved the SessionToken as in the last example, I use its key to retrieve the User like:
//... then retrieve the User
user = pm.getObjectById(User.class, tokens.get(0).getKey().getParent());
//return retireved user if any...
This way I do a key lookup instead of another query, but anyway I still access the Datastore twice...
Upvotes: 1
Views: 414
Reputation: 153
Query query = pm.newQuery(User.class);
query.setFilter("sessionToken == tokenParam && tokenParam == 'my_token'");
query.declareParameters(SessionToken.class.getName() + " tokenParam");
should work
Upvotes: 0
Reputation: 760
One possible solution is to have a bidirectional owned one-to-one relationship between your two entity classes. Then you can:
SessionToken
you want by querying on token.SessionToken
's parent User
by calling the appropriate getter method of the obtained SessionToken
.Another possible solution is to follow "Executing Simple Joins Across Owned Relationships" as set out in the "Google App Engine Java Persistence" blog.
Upvotes: 1