I was trying to use Hibernate Annotations, which I think is great … I am happy with it… but I learnt some stuff which I know I will forget. So I am blogging it here, hopefully I will make sense and serve as a reminder for me when I need it. Maybe it might help someone else too… who knows…
Bidirectional One-To-Many
here I am trying to create a Bidirectional One-To-Many relationship between Question and Choice, a Question has many choices.
- Setup entities
@Entity
@Table (name = "QUESTION")
public class Question implements Serializable
{@Id
@GeneratedValue (strategy = GenerationType.AUTO)
@Column (name = “QUESTION_ID”)
private Long id;@Column (name = “TEXT”)
private String text;
……………
@Entity
@Table (name = "CHOICE")
public class Choice implements Serializable
{@Id
@GeneratedValue (strategy = GenerationType.AUTO)
@Column (name = “CHOICE_ID”)
private Long id;@Column (name = “TEXT”)
private String text;
…………… - Setup the ONE side on Question – I read ONE Question has MANY CHOICE(S).
Question
@OneToMany (mappedBy="question")
private Set choices = new HashSet();
mappedBy – means “I am not the owner side”, I am mapped by question from the other side of the relationship. It will also not create the database column which makes sense, I would expect a foreign key on the CHOICE table instead.
- Setup the Many side on Choice – I read on Choice.java MANY Choice has ONE Question
@ManyToOne
@JoinColumn (name="QUESTION_ID")
private Question question;
the @JoinColumn indicate the owning side of the relationship, it is responsible for updating the database column. It will create the QUESTION_ID column on the CHOICE table
- Reversing the Relationship so that the owning side is the Question instead
Question
@OneToMany
@JoinColumn (name = "QUESTION_ID")
private Set choices = new HashSet();
Choice
@ManyToOne
@JoinColumn (name="QUESTION_ID", updatable = false, insertable = false)
private Question question;
- Finally I need to use a List instead of Set – so I can preserve the order of the Choice(s).Question
@OneToMany (
cascade = {CascadeType.ALL},
fetch = FetchType.EAGER
)
@JoinColumn (name = "QUESTION_ID")
@org.hibernate.annotations.Cascade(
value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN
)
@org.hibernate.annotations.IndexColumn(name = "CHOICE_POSITION")
private List choices = new ArrayList();
Choice
@ManyToOne
@JoinColumn (name="QUESTION_ID", nullable = false, updatable = false, insertable = false)
private Question question;
the @org.hibernate.annotations.IndexColumn defines the colum CHOICE_POSITION that will be used to maintain the order of the list. Some how reversing the ownership is the only way to get the IndexColumn to work









28 responses so far ↓
Taras // December 6, 2006 at 12:28 am |
Hi!
One question about @IndexColumn – I have to create field “CHOICE_POSITION” (as posted in your example) in db or not? If yes, then on what side of relationship? Thanks for response.
josian // December 7, 2006 at 9:53 am |
Yes, the column needs to be created but what I do is use the configuration.generateSchemaCreationScript(dialect);
which will automatically create the schema for me.
HTH
Wheazel // January 8, 2007 at 11:53 pm |
Ty, really helped me out. Your example is way easier then the reference one.
Prashant Khanal // February 9, 2007 at 1:37 pm |
Hey i am new to hibernate.
I am really confused about what are the advantages of bidirectional one-to-many over unidireational.i found this configuration hits the database with more queries than unidirectional. One more thing what is the use of IndexColumn.
josian // February 14, 2007 at 2:08 pm |
I am not an expert either, but I suppose having a bidrectional mapping gives you flexibility and really depends on how you want to use your Pojos.
If you always access/use your “child” objects from the parent object, then there’s is no need to make them bi-directional
“IndexColumn” here is needed as I wish to maintain the order of the list. So that when I retrieve a “List” of “Choice” objects its order is preserve as the way I had put them in in the first place.
HTH
Nick // March 13, 2007 at 2:04 pm |
If I use “IndexColumn” and then insert new elements (Choices) into the list after the Question has already been stored in the database, will all indexes be updated for the Question on the next merge()?
josian // March 16, 2007 at 2:04 pm |
Yea I think so yes. I vaguely remember it as such. the indexColumn gets updated according to the order of the List. Give it a go
Marcelo // May 17, 2007 at 9:48 pm |
Thank you for the example, it´s so simple and great!
Mike D. // August 10, 2007 at 2:19 am |
Great example, thanks!
Obi Wan // August 24, 2007 at 6:20 am |
How about if we want to join two tables foe OneToMany on different column names from both tables . What I mean that In one table I have column serverId and in other, I have SId and I need to join them
josian // August 24, 2007 at 8:17 am |
If you take a read at step 3, you can actually specify the column name in the “JoinColumn”.
So in your case I suppose it would be :
@ManyToOne
@JoinColumn (name=”SId”)
private Server server;
HTH
Jaap // August 30, 2007 at 12:50 am |
Thanks for this example, it helped me out a lot!
Fred // August 31, 2007 at 12:30 am |
Hi, I tried the IndexColumn in my DB (Oracle) and it didn´t work. The index column remains empty (no value at all), despites of the list´s size (I tried many list sizes).
Bruce LeSourd // October 18, 2007 at 1:25 am |
Why did you add
@org.hibernate.annotations.Cascade(
value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN
)
in Step 5. This would seem to be redundant with or override
cascade = {CascadeType.ALL},
also on the Question.choices relationship.
Alan Jelden // November 30, 2007 at 12:22 am |
Great example! I’m not sure why it seems so difficult to find a straight forward example like this. I’ve got a question about step 4. It seems that after step 3, everything should be setup just fine. What is the point of reversing the relationship. Also, what does the term “owner” of the relationship mean to you?
SVK // January 1, 2008 at 3:36 pm |
Hi,
When retrieving the list, would it return in some order? I mean using @IndexColumn, its always returning in the descending sort. Is there a way we could specify this order or is it some default?
josian // January 28, 2008 at 6:43 pm |
I vaguely remember that DELETE_ORPHAN is a hibernate extension and not part of JPA….
Bruce LeSourd Says:
October 18, 2007 at 1:25 am e
Why did you add
@org.hibernate.annotations.Cascade(
value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN
)
in Step 5. This would seem to be redundant with or override
cascade = {CascadeType.ALL},
also on the Question.choices relationship.
josian // January 28, 2008 at 6:50 pm |
Regarding ordering the List using IndexColumn, I believe you can change the base from 0 to 1 like :
@org.hibernate.annotations.IndexColumn(name = “step_ordering”, base=1)
but I don’t think there’s a way to inverse it, if you want to keep it, it should just return you the list the way you put in… I also remember reading somewhere that you can specify retrieving in some order but not using @IndexColumn I think
HTH
SVK Says:
January 1, 2008 at 3:36 pm e
Hi,
When retrieving the list, would it return in some order? I mean using @IndexColumn, its always returning in the descending sort. Is there a way we could specify this order or is it some default?
i0n // February 23, 2008 at 8:45 am |
Hi. this help me very much.
But Work for me in a DB2/as400 in this form:
@Entity
public class tstEntity1 implements Serializable {
private Long id;
private List lista = new LinkedList();
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@org.hibernate.annotations.IndexColumn(name = “INDICE”)
public List getLista()
…
And the other class definition
@Entity
public class tstEntity2 implements Serializable {
private Long id;
private tstEntity1 padre;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {…
@ManyToOne
@JoinColumn(name = “ID”, nullable = false, updatable = false, insertable = false)
public tstEntity1 getPadre() {…
i0n // February 23, 2008 at 9:19 am |
well may last post. work in a erratic way
Marek // April 11, 2008 at 8:33 pm |
Why not to use LinkedHashSet instead of LinkedList? In my particular case I need unique elemenst in collection. You mentioned that it’s all about holding order. So why not LinkedHashSet?
bascht // April 16, 2008 at 8:08 pm |
Thank you.
nikhil // June 20, 2008 at 9:15 am |
Thanks dude!
Parmendra // October 14, 2008 at 9:05 pm |
How to use @JoinColumn in @OneToMany case ?
Suppose in bidirectional association you defin @JoinColumn at @OneToMany side, is it still required to define @JoinColumn at @ManyToOne side.
jose // March 2, 2009 at 10:28 pm |
Thank you! It makes perfect sense all your explanations! I’ve been going crazy untill I found you’re post. Do you know why is it not working the indexColumn if we use it on the other side?
jose // March 2, 2009 at 11:46 pm |
I have one problem with this way of working. In my case I have and object A than contains a List of object B and B contains a List of C.
this solution means that if I want to insert and object C I have to get the whole Object A and then update the C list, it looks really ineficient. If I don’t want to get the whole object A I have to manage the index manually and I don’t think it’s the best choice.
can you help me out?
cheers
Sagappeno // April 22, 2009 at 8:59 pm |
mm.. good one )
» Hibernate: Bidrektinales Mapping mit IndexColumn // May 12, 2009 at 5:38 pm |
[...] Danke an: http://josian.wordpress.com [...]