JPA, Hibernate: составной ключ с ассоциациями. Почему загружается, но не сохраняется?

Я пытаюсь сопоставить 3 объекта: вопрос, ответ и вопросдисплейруле. Вопрос имеет много ответов и множество правил отображения вопросов, каждое из которых относится к одному вопросу. QuestionDisplayRule имеет один вопрос, один ответ и одно поле со строковым значением. Таблица db для QuestionDisplayRule выглядит следующим образом:

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

Естественно, question_id и answer_id — это ПК.

Отображение JPA выглядит следующим образом:

@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;
}

а также

@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;

}

Проблема в том, что он отлично загружает QuestionDisplayRules, если я добавляю записи вручную в БД, но не сохраняю их. Ни ошибок, ничего..

Тестовый код:

    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);

Любые идеи? Спасибо!


person Maxim Suponya    schedule 10.02.2012    source источник
comment
Почему вы используете составные ключи? По уважительным причинам это не рекомендуется Hibernate и JPA. И почему у вас есть ассоциация с Question в QuestionDisplayRule? В этом нет необходимости, так как у него уже есть toOne to Answer, у которого есть toOne to Question. Придерживайтесь автоматически сгенерированных идентификаторов в один столбец, и ваша жизнь станет намного проще. И, наконец, вы сопоставляете одну и ту же ассоциацию дважды: один раз в идентификаторе и один раз в сущности.   -  person JB Nizet    schedule 10.02.2012
comment
Сопоставление вопроса в QuestionDisplayRule, потому что это вопрос, отличный от того, на который ссылается ответ. QuestionDisplayRule похож на «Отобразить этот вопрос, если ответ на этот ответ (и впоследствии этот вопрос) соответствует answerValue». И я не хочу вводить идентификатор одного столбца, потому что это заставляет меня чувствовать, что дизайн моей базы данных продиктован Hibernate. На это не должно влиять. Фреймворки приходят и уходят, данные остаются годами.   -  person Maxim Suponya    schedule 13.02.2012


Ответы (1)


Вы сопоставляете сущности во встраиваемых объектах, это неправильно. Встраиваемый объект должен содержать только базовые типы. Короче говоря, ваши объекты должны выглядеть так:

@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;
}
person siebz0r    schedule 07.06.2012