0

Regarding the following example, is it possible to retrieve list of AnsweredQuestion instances as objects of Question?

@MappedSuperclass
public abstract class Question{
  @Column(name="TITLE")
  private String title;
  ...
}

@Entity
@Table(name="ANSWEREDQUESTION")
public class AnsweredQuestion extends Question
{
  @Column(name="ANSWER")
  private String answer;
  ...
}

It is very important for me to retrieve only a few columns since the descendant class has many. I tried something as follows, but it still returns list of AnsweredQuestion:

queryStr = " select q from AnsweredQuestion q where ..."
TypedQuery<Question> query = entityManager.createQuery(queryStr, Question.class);
return query.setParameter( ... ).getResultList();
Bartek
  • 169
  • 9
  • 1
    No: 1. Can not instantiate an abstract class 2. You select from `AnsweredQuestion` - and so you get them – TheConstructor Oct 05 '14 at 19:22
  • You may also have a look at this: http://stackoverflow.com/a/6532840/1266906 – TheConstructor Oct 05 '14 at 19:26
  • Is it possible to get that kind of a result using some other kind of inheritance strategy? – Bartek Oct 05 '14 at 20:49
  • JPA cannot use setters on non-entity objects, but there is nothing stopping you from also mapping the Question as a read-only entity to the same ANSWEREDQUESTION table. Then you can read using Question when you what the minimal selection options, and using AnsweredQuestion when you want to make updates. – Chris Oct 06 '14 at 00:36
  • @Chris: how to map entity as read-only? I couldn't find anything bout that, at least in hyperjaxb docs. I tried to simply set the same Table name for both Entities, but then I got a hibernate exception at the application start when database is created. – Bartek Oct 06 '14 at 17:37
  • I don't know Hibernate well, I was thinking of a different provider. JPA inheritance isn't what you want for this, as querying on a root requires JPA to give you back all subclass instances, and it will corrupt your cache. You will probably need a new ShortQuestion class with Question still marked as a MappedSuperclass. As long as you don't modify ShortQuestion instances, it doesn't matter if they are marked read-only somehow in the provider. – Chris Oct 07 '14 at 16:04

1 Answers1

2

If you need to return a few fields, you can also select them and use the new operator:

TypedQuery<Sample> query = entityManager.createQuery("select new com.acme.sample.Sample(e.fieldA, e.fieldB) from  AnsweredQuestion e", Sample.class);
return query.setParameter( ... ).getResultList();

JPA implementation will look for a Sample constructor (the path must be complete) and invoke it while transforming the result. It is pretty handy (at the cost of creating new classes to represent the result) to avoid returning everything the database has to return :)

NoDataFound
  • 11,381
  • 33
  • 59
  • I am afraid that TREAT won't be applicable for this issue. I tried with the syntax you suggested, and got org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: treat (...). I couldn't find any examples of "select **TREAT**" on the internet, but it seems that it is used always after **JOIN** and always to cast super class to a child. Regarding second suggestion, both Question and DetailedQuestion are generated by HyperJaxb, so I can't add constructors to them. Or maybe there is a way to make Jaxb generate a constructor? Or to use setters in JPA query? – Bartek Oct 05 '14 at 20:35
  • Then create some random POJO. And I don't know Hyperjaxb. – NoDataFound Oct 05 '14 at 20:50
  • TREAT is used with JPA inheritance and not applicable here because Question is not an entity. Treat does not require a join, but if it isn't over a relationship you don't need to use Treat, you would just Select from Question instead of AnsweredQuestion anyway. – Chris Oct 06 '14 at 00:31
  • I've updated my answer to remove the `TREAT` part, and left the `select next`. – NoDataFound Oct 06 '14 at 11:58
  • @Chris I tried to define Entities for both Question and AnsweredQuestion, and when I used "select q from Question q..." it always returned instances of AnsweredQuestion (I tried inheritance strategy JOINED and SINGLE TABLE). This is not what I want, because after records are retrieved they are sent as a WebService result, and since they are instances AnsweredQuestion Jaxb marshals all of the columns. In other words, too much data is retrieved. – Bartek Oct 06 '14 at 18:13
  • You want to restrict the queries using the "TYPE(q)=Question" clause, but see my comment on the question itself that this might not be a great idea for your cache. You will want to create a new branch Entity, but this is hijacking NoDataFound's answer. – Chris Oct 07 '14 at 16:09
  • Don't hijack me :P I personally like the `select new` as it's more like what SQL is. You often don't want to select all but only a part of your entity but that should not be your primary concern (eg: optimizing versus what do I need to do with the data ?). I'd say use `select new` or equivalent to do what you want when you know you will really hurt the performance (I use `select new` for case where I have 260k rows returned by the query). – NoDataFound Oct 07 '14 at 21:04