Kind of an involved question, but I'm wondering if it's possible to
use the "parent-key" pattern with JPA to search for N child entities
of a given parent that have a particular property. I can get this to
work if I include the parent object in my child entity, but I'd like
it to work when I just hold the parent's Key (as opposed to having to
hold a reference to the entire parent).
Some sample code below illustrates things. I have two entities,
called "Parent" and "Child". Notice that my Parent class has a String-
based entity id, while the Child class has a GAE "Key" entity id.
The first example shows the "Child" class holding a full "Parent"
class. In the setup below, I can execute a Query that says, "select
key from Children where parent = :parent and tag = :tag", passing in a
full "Parent" object into the EntityManager like so:
//////////////////////////////
// QUERY THAT WORKS
//////////////////////////////
Parent parent = [get Parent object with id "john" from datastore]
[//Assume that a "Child" object exists in the DS who parent is "john"
and with a tag of "the-tag"]
em = EMF.get().createEntityManager();
Query jpaQuery = em.createQuery("select key from Child where parent
= :parent and tag = :tag");
jpaQuery.setParameter("tag", "the-tag");
//Use the full parent object here...
jpaQuery.setParameter("parent", parent);
Key childKey = (Key) jpaQuery.getSingleResult();
///////////
// Parent Class
///////////
class Parent
{
private String id;
private List<Child> children;
@Id
public String getId()
{ return id; }
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL,
mappedBy="parent")
public List<Child> getChildren()
{ return this.children; }
}
///////////
// Child Class
///////////
class Child
{
private Key key;
private List<String> tags;
private Parent parent;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private getKey()
{ return this.key; }
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public Parent getParent ()
{ return this.parent; }
...<snip>
}
If I try to use the parent-key pattern, things start to break down a
bit. First, notice that the "Child" class no longer has an entire
"Parent" instance variable. Instead, there is a Key field, and a
Datanucleus extension annotation. In the "Parent " class, the
"mappedBy" parameter has been removed because leaving it causes an
exception saying mappedBy fields must be complete Entities.
///////////
// Tweaked Parent Class
///////////
class Parent
{
private String id;
private List<Child> children;
@Id
public String getId()
{ return id; }
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
public List<Child> getChildren()
{ return this.children; }
}
///////////
// Tweaked Child Class
///////////
class Child
{
private Key key;
private List<String> tags;
private Parent one;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private getKey()
{ return this.key; }
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@Extension(vendorName = "datanucleus", key = "gae.parent-pk", value =
"true")
public Key getParentKey()
{ return this.parentKey; }
...<snip>
}
Using the above pattern, if I create an instance of "Parent" in the
datastore, the "Child" class is not created in the datastore, even
though I've created it in Java. Executing the Query from above
produces: "javax.persistence.NoResultException: No results for query:
SELECT key FROM..."
Am I doing something wrong here?
--
You received this message because you are subscribed to the Google Groups
"Google App Engine for Java" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-appengine-java?hl=en.