I'm using JPA on GAE and this query return a List containing 1 element. This element is a org.datanucleus.store.types.sco.backed.ArrayList (and it's finally containing my results) while I'm expecting a List of Products. What's I'm doing wrong? Thanx in advance!
Query query = entityManager.createQuery("select p.products from Place p where p.id = :Id" );
query.setParameter("Id",id);
List<Product> resultList = query.getResultList();
//for debugging purpose
assert (resultList.get(0) instanceof Product);
if (resultList.size() > 0)
{
//raise a cast exception here
Product p = resultList.get(0);
}
@Entity
public class Place {
private Collection<Product> products;
@OneToMany(cascade = CascadeType.ALL)
public Collection<Product> getProducts() {
return products;
}
public void setProducts(Collection<Product> products) {
this.products = products;
}
private String id;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
That class javadoc tells that it implements java.util.List, so it is a valid return type.
Remember that the specification says that you get a List as a return type, not a java.util.ArrayList, so any class that implements List is as valid as any other.
UPDATE:
Try:
SELECT pr FROM Place pl INNER JOIN pl.products pr WHERE pl.id = :Id
I not much familiar with DataNucleus, so haven't executed. But with JPA, the query should work fine. You can try the below code to build query, which returns results according to the specified class.
entityManager.createQuery("SELECT p.products FROM Place p WHERE p.id = :Id", Product.class);
From Documentation :
<T> TypedQuery<T> createQuery(java.lang.String qlString,
java.lang.Class<T> resultClass)
Create an instance of TypedQuery for executing a Java Persistence query language statement. The select list of the query must contain only a single item, which must be assignable to the type specified by the resultClass argument.
Parameters:
qlString - a Java Persistence query string
resultClass - the type of the query result
I am not much familiar with DataNucleus, so haven't executed. But with JPA, the query should work fine. You can try the below code to build query, which returns results according to the specified class.
entityManager.createQuery("SELECT p.products FROM Place p WHERE p.id = :Id", Product.class);
From Documentation :
<T> TypedQuery<T> createQuery(java.lang.String qlString,
java.lang.Class<T> resultClass)
Create an instance of TypedQuery for executing a Java Persistence query language statement. The select list of the query must contain only a single item, which must be assignable to the type specified by the resultClass argument.
Parameters:
qlString - a Java Persistence query string
resultClass - the type of the query result
Edit : You can try the following code.
Place place = entityManager.createQuery("SELECT p FROM Place p WHERE p.id = :Id", Place.class).getSingleResult();
List<Products> products = place.getProducts();
Also as a side-note, you are using JPA, but @Extension seems to be JDO specific annotation.
Selecting a multi-valued field from a JPQL query is a very strange thing to do (when you think how the results are to be returned - i.e multiple values in a single result "row"). If you want the "products" for a Place then you retrieve the Place and it has the products.
Selecting a multi-valued field from a JPQL query is illegal when the JPQL spec says the select item should be
"single_valued_path_expression | scalar_expression | aggregate_expression |
identification_variable | OBJECT(identification_variable) | constructor_expression"
so answers saying this query is correct are wrong. If you want the "products" for a Place then you retrieve the Place and it has the products.