1

I'm trying to map 3 entities: Question, Answer and QuestionDisplayRule. Question has many Answers and many QuestionDisplayRules each of which belong to one Question. QuestionDisplayRule has one Question, one Answer and one field with String value. The db table for QuestionDisplayRule looks like this:

create table question_display_rule(
    question_id int, 
    answer_id int, 
    answer_value varchar(128)
);

Naturally, question_id and answer_id are the PK.

JPA mapping looks like this:

@Embeddable
public class QuestionDisplayRulePK implements Serializable {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="question_id", insertable = false, updatable = false)
    private Question question;

    @ManyToOne
    @JoinColumn(name = "answer_id", insertable = false, updatable = false)
    private Answer answer;
}

and

@Entity
@Table(name = "question_display_rule")
public class QuestionDisplayRule implements Serializable {

    @EmbeddedId
    private QuestionDisplayRulePK id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="question_id", insertable = false, updatable = false)
    private Question question;

    @ManyToOne
    @JoinColumn(name = "answer_id", insertable = false, updatable = false)
    private Answer answer;

    @Column(name="answer_value")
    private String answerValue;

}

The problem is that it loads QuestionDisplayRules just fine if I add records manually in the DB but won't save them. No errors, no nothing..

Test code:

    QuestionDisplayRulePK qPK = new QuestionDisplayRulePK();
    qPK.setQuestion(q);
    qPK.setAnswer(a);

    QuestionDisplayRule qr = new QuestionDisplayRule(qPK, "Yes");
    qr.setAnswerValue("whateva..");

    ....
    // DAO code looks like: getSession().saveOrUpdate(qr);

Any ideas? Thanks!

Maxim Suponya
  • 1,419
  • 2
  • 20
  • 43
  • Why are you using composite keys? This is discouraged, for good reasons, by Hibernate and JPA. And why do you have an association to Question in QuestionDisplayRule? It's not necessary, since it already has a toOne to Answer, which has a toOne to Question. Stick to single-column auto-generated IDs, and your life will be much easier. And finally, you're mapping the same association twice: once in the ID, and once in the entity. – JB Nizet Feb 10 '12 at 08:11
  • Mapping Question in QuestionDisplayRule because it's a different question than the one Answer references. QuestionDisplayRule is like 'Display this Question if answer to this Answer(and subsequently that Question) matches answerValue'. And I don't want to introduce a single column id because it makes me feel like my database design is dictated by Hibernate. It should have no influence on it. Frameworks come and go, the data stays for years.. – Maxim Suponya Feb 12 '12 at 23:24

1 Answers1

1

You're mapping entities in an embeddable, this is wrong. An embeddable should only contain base types. In short your entities should look like this:

@Entity
public class Question
{
    @Id
    @GeneratedValue
    @Column(name = "id")
    private Long id;
    @OneToMany(mappedBy = "question")
    private Set<Answer> answers;
}

@Entity
public class Answer
{
    @Id
    @GeneratedValue
    @Column(name = "id")
    private Long id;

    @ManyToOne
    private Question question;
}

@Entity
public class QuestionDisplayRule
{
    @EmbeddedId
    private QuestionDisplayRulePK key;

    @MapsId(value = "questionId")
    @ManyToOne
    @JoinColumn(name = "question_id", referencedColumnName = "id")
    private Question question;

    @MapsId(value = "answerId")
    @ManyToOne
    @JoinColumn(name = "answer_id", referencedColumnName = "id")
    private Answer answer;
}

@Embeddable
public class QuestionDisplayRulePK
{
    @Column(name = "answer_id")
    private Long answerId;
    @Column(name = "question_id")
    private Long questionId;
}
siebz0r
  • 18,867
  • 14
  • 64
  • 107