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.

  1. 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;
    ……………

  2. 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.

  3. 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

  4. 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;

  5. 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

23 Responses to “Hibernate Annotations - Bidirectional One-To-Many”

  1. Taras Says:

    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.

  2. josian Says:

    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

  3. Wheazel Says:

    Ty, really helped me out. Your example is way easier then the reference one.

  4. Prashant Khanal Says:

    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.

  5. josian Says:

    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

  6. Nick Says:

    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()?

  7. josian Says:

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

  8. Marcelo Says:

    Thank you for the example, it´s so simple and great!

  9. Mike D. Says:

    Great example, thanks!

  10. Obi Wan Says:

    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

  11. josian Says:

    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

  12. Jaap Says:

    Thanks for this example, it helped me out a lot!

  13. Fred Says:

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

  14. Bruce LeSourd Says:

    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.

  15. Alan Jelden Says:

    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?

  16. SVK Says:

    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?

  17. josian Says:

    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.

  18. josian Says:

    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?

  19. i0n Says:

    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() {…

  20. i0n Says:

    well may last post. work in a erratic way :(

  21. Marek Says:

    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?

  22. bascht Says:

    Thank you.

  23. nikhil Says:

    Thanks dude!

Leave a Reply