0

I am developing a Q&A-style web application in which two of the entities are Question and Answer. A Question has-many Answers. In addition, an Answer has-many Answers (which I refer to as child answers of an answer):

@Entity
@Table(name = "questions")
public class Question implements Serializable {

    @Id
    private Long id;

    @OneToMany(mappedBy = "question")
    private Set<Answer> answers;

    //...
}

@Entity
@Table(name = "answers")
public class Answer implements Serializable {

    @Id
    private Long id;

    @ManyToOne
    private Question question;

    @ManyToOne
    private Answer parentAnswer;

    @OneToMany(mappedBy = "parentAnswer")
    private Set<Answer> childAnswers;

    //...
}

When fetching child answers of a specific answer, Hibernate uses a query similar to:

select ... from answers childanswe0_ where childanswe0_.parent_answer_id=?

What I would like to do is customize the WHERE clause so that the question ID is also included; I would like something like this:

select ... from answers childanswe0_ where
   childanswe0_.question_id=? and childanswe0_.parent_answer_id=?

The reason why is that I have an index on answers(question_id, parent_answer_id) that I would like to be used. I do not currently have, and I do not want to add, an index on answers(parent_answer_id), so the current query results in a full table scan.

I tried using @JoinColumns on the childAnswers field, but this resulted in the error: org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn: test.domain.Answer.childAnswers

I also tried using @JoinColumns on the parentAnswer field, but this resulted in the error: org.hibernate.AnnotationException: A Foreign key refering test.domain.Answer from test.domain.Answer has the wrong number of column. should be 1

My JPA provider is Hibernate 5.2.17.

How do I ensure that the WHERE clause of the query used to select the child answers of a parent answer includes the parent answer's question ID?

Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193
  • What are you trying to return, the answer or the parent answer? Isn't it "from Answer a where a.parentAnswer.question = ?" – K.Nicholas Jul 12 '18 at 21:09
  • Well, the most natural solution would be for the `Answer` entity to have a composite primary key (`id` + `question`). This way, Hibernate would be forced to use both for fetching child entities. Are you sure the query results in unindexed lookup, though? I would expect the db to be clever enough to use your index for partial lookup – crizzis Jul 12 '18 at 21:10
  • Possible duplicate: https://stackoverflow.com/questions/432347/how-to-do-custom-query-based-collection-mappings-in-hibernate – JimmyB Jul 12 '18 at 21:16
  • @crizzis Neither hibernate nor the RDBMS can, from what they are given via the annotations, know that an answer's question is always the same as the parent-answer's question. – JimmyB Jul 12 '18 at 21:17
  • @JimmyB I never said they could, I meant that a clever RDBMS uses multi-valued indices for single-value lookup, the kind of lookup that `childanswe0_.parent_answer_id=?` requires – crizzis Jul 12 '18 at 21:23
  • 1
    @crizzis Any RDBMS I've ever seen can only use an index's *prefix* for partial matching. The composite index (question_id, parent_answer_id) will be used when querying for only question_id but cannot be used without a question_id. - If that weren't the case we'd have only one index on every table which contains all the columns we may ever want to query by; but that's not how indexes work. – JimmyB Jul 12 '18 at 21:26
  • @JimmyB You're absolutely right, I didn't pay enough attention to the field ordering. I guess the suggestion is, then, to consider flipping the field order. Obviously, whether that's a sound idea depends on the specific use cases. It seems it would make sense if the application fetches top-level answers first and child answers on demand – crizzis Jul 12 '18 at 21:37
  • 1
    Reconsider your data model. Conceptually, why is an answer to an answer the same (type) as an answer to a question? An answer-to-answer can somehow *relate* to a query but primarily link to its parent answer. Makes me think about the purpose of the question entity for the answer-to-answer. Is it really needed or is it a proxy for a concept of a forum *thread* or some other structure which happens to be mostly in 1:1 relationship with a question? – JimmyB Jul 12 '18 at 21:48

0 Answers0