Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA 2.0 Hibernate @OneToMany + @MapKeyJoinColumn

OneToMany + MapKeyJoinColumn doesn't work for me, please suggest what I'm doing wrong.

I'm using JPA 2.0 + Hibernate 3.6.1 And want to map following tables:


Question to Statement to Language relationship


To Classes:



@Entity
public class Question {
    // id and other fields

    @OneToMany(mappedBy="question", cascade = CascadeType.ALL)
    @MapKeyJoinColumn(name="language_id")
    private Map<Language, Statement> statements =
        new HashMap<Language, Statement>();
}

@Entity
public class Statement {
    @Id
    private Long id;

    @ManyToOne
    @JoinColumn(name = "language_id", nullable = true)
    private Language language;

    @ManyToOne
    @JoinColumn(name = "question_id", nullable = false)
    private Question question;

    @Column(name = "message")
    private String message;
}

@Entity
public class Language {
    @Id
    private Long id;

    @Column(name = "name")
    private String name;
}

But it doesn't work. EntityManager persists it correctly, but when I retrieve Question, in it's statements map there is only one language-to-null entry. Please, help


Edit1: Strange, but when I preload all Languages, like this:


String sql = "select l from Language l";
List languages = entityManager.createQuery(sql, Language.class).getResultList();

then it works!
Does anybody know how to make hibernate automatically load all objects of certain class?

like image 906
jnr Avatar asked Feb 22 '11 10:02

jnr


1 Answers

In fact, the id property in your class Statement must be a composite primary key. You do not need a statement_id in your table Statement. The primary key is composed of both language_id and question_id.

Try that :

    @Entity
    public class Statement implements Serializable {

        private static final long serialVersionUID = 1L;

        @EmbeddedId
        private StatementId id = new StatementId();

        @Column(name = "message")
        private String message;
    }

    @Embeddable
    private static class StatementId implements Serializable {

        private static final long serialVersionUID = 1L;

        StatementId(){}

        @ManyToOne
        private Question product;

        @ManyToOne
        private Language language;

    }

And do not forget the fetchType in Question in order to avoid LazyInitializationExceptions.

public class Question {

    @OneToMany(mappedBy="id.question", fetch=FetchType.EAGER)
    @MapKeyJoinColumn(name="language_id")
    private Map<Language, Statement> statements = new HashMap<Language, Statement>();
}

Hope it will help.

like image 147
rico Avatar answered Oct 24 '22 20:10

rico