Skip to main content

Problem with @Inheritance, collection-valued field in subclass

2 replies [Last post]
cayhorstmann
Offline
Joined: 2003-06-13

I have a problem with a collection-valued field in a subclass. The collection in the subclass doesn't get fetched.

Here is the example:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Question implements Serializable {
private int id;
private String text;
private String answer;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() { return id; }
public void setId(int id) { this.id = id; }
// trivial getters and setters for text, answer omitted
}

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class ChoiceQuestion extends Question {
private Collection choices;
@OneToMany(mappedBy="question", fetch=FetchType.EAGER)
public Collection getChoices() { return choices; }
public void setChoices(Collection choices) { this.choices = choices; }
}

@Entity
public class Choice implements Serializable {
private int id;
private String text;
private ChoiceQuestion question;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public int getId() { return id; }
public void setId(int id) { this.id = id; }
@ManyToOne
@JoinColumn(name="Question_Id")
public ChoiceQuestion getQuestion() { return question; }
public void setQuestion(ChoiceQuestion question) { this.question = question; }
// trivial getter and setter for text omitted
}

I populate the database with a ChoiceQuestion that has several choices. The data is put into the tables correctly.

I then issue this EJBQL query:

SELECT q FROM ChoiceQuestion q WHERE q.text = :text

I get a ChoiceQuestion with an empty "choices" collection.

Is this a bug, or am I overlooking something silly?

Thanks,

Cay

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mperezma
Offline
Joined: 2005-03-22

Hello Cay,

I'm just starting with persistence API right now, and have been playing with your code.. It works fine for me!... I'm using glassfish b33 libraries.

How do you populate the data? Try it this way:


public class QuestionsTest {
private static EntityManagerFactory emf;
private static EntityManager em;

public static void main(String[] args) {
emf = Persistence.createEntityManagerFactory("pu1");

em = emf.createEntityManager();
em.getTransaction().begin();

ChoiceQuestion question = new ChoiceQuestion();
question.setText("¿Quién descubrió América?");
question.setAnswer("Cristobal Colón");

em.persist(question);

Choice choice1 = new Choice();
choice1.setQuestion(question);
choice1.setText("Cristobal Colón");

Choice choice2 = new Choice();
choice2.setQuestion(question);
choice2.setText("Santiago de Compostela");

em.persist(choice1);
em.persist(choice2);

Vector choices = new Vector();
choices.add(choice1);
choices.add(choice2);

question.setChoices(choices);

em.getTransaction().commit();
em.close();

em = emf.createEntityManager();
em.getTransaction().begin();

Query q = em.createQuery("SELECT q FROM ChoiceQuestion q WHERE q.text = :text");
q.setParameter("text", "¿Quién descubrió América?");
ChoiceQuestion cq = (ChoiceQuestion)q.getSingleResult();

System.out.println("Question: " + cq.getText());

for(Choice c : cq.getChoices())
System.out.println("Choice: " + c.getText());

em.getTransaction().commit();
em.close();

}
}

I get this output:

Question: ¿Quién descubrió América?
Choice: Santiago de Compostela
Choice: Cristobal Colón

If you map the relationship this way in ChoiceQuestion sublcass:


@OneToMany(mappedBy="question", cascade=CascadeType.ALL)
public Collection getChoices() {
return choices;
}

public void setChoices(Collection choices) {
this.choices = choices;
}

then you can populate this way:


em = emf.createEntityManager();
em.getTransaction().begin();

ChoiceQuestion question = new ChoiceQuestion();
question.setText("¿Quién descubrió América?");
question.setAnswer("Cristobal Colón");

em.persist(question);

Choice choice1 = new Choice();
choice1.setQuestion(question);
choice1.setText("Cristobal Colón");

Choice choice2 = new Choice();
choice2.setQuestion(question);
choice2.setText("Santiago de Compostela");

question.getChoices().add(choice1);
question.getChoices().add(choice2);

em.getTransaction().commit();
em.close();

hope this help

mariO

PS: Anybody knows how to format code in this forum?

cayhorstmann
Offline
Joined: 2003-06-13

Better late than never...I just wanted to tell you that you are right. Inheritance had nothing to do with it. I failed to set up the bidirectional relationship in the POJOs.

I thought that setting up the owning direction was enough. After all, that is all that is required for the database.

The moral from this (and from http://forums.java.net/jive/thread.jspa?threadID=2657&tstart=0) is "Don't cheat those POJOs--set up the relationships on both sides." :-)

Cay