Hibernate Annotations – Bidirectional One-To-Many

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

About these ads

48 responses to “Hibernate Annotations – Bidirectional One-To-Many

  1. 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. 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. Ty, really helped me out. Your example is way easier then the reference one.

  4. Prashant Khanal

    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. 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. 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. 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. Thank you for the example, it´s so simple and great!

  9. Great example, thanks!

  10. 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. 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. Thanks for this example, it helped me out a lot!

  13. 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. 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. 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. 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. 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. 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. 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. well may last post. work in a erratic way :(

  21. 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. Thanks dude!

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

  24. 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?

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

  26. Pingback: » Hibernate: Bidrektinales Mapping mit IndexColumn

  27. Everytime _the_ resource where I solve my (standard) problems. Great idea, great examples – thanks :-)

  28. William Antônio Siqueira

    Thanks, this help-me a lot /

  29. Ricardo Espergue

    Awesome explanation, I have hard time searching for list mapping ordering.

    Good Job!

  30. can you extend your example with Answer Entity
    which will have oneToOne relation with Question
    with question_id has shared primary key.

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

    @OneToMany(cascade = CascadeType.ALL, mappedBy = “flHdr”)
    @JoinColumn (name = “QUESTION_ID”)
    private Set choices = new HashSet();

    @OneToOne
    private Answer answer;
    }
    @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;
    ……………

    @ManyToOne
    @JoinColumn (name=”QUESTION_ID”, updatable = false, insertable = false)
    private Question question;
    }

    @Entity
    @Table (name = “ANSWER”)
    public class Answer implements Serializable
    {
    @Id
    @GeneratedValue(generator = “foreign”)
    @GenericGenerator(name = “foreign”, strategy = “foreign”,
    parameters = {@Parameter(name = “property”, value = “question”)})
    private Long id;

    @Column (name = “answer”)
    private String answer;

    @OneToOne
    @PrimaryKeyJoinColumn
    private Question question;
    …….
    }

    is the above code will do any changes needed because of i am getting exception.
    @OneToOne or @ManyToOne on com.sample.Choice.question references an unknown entity: com.sample.Question

  31. That is good post..well i am having a problem and it is driving me nuts.
    i have a scenario in which each product it link to some other product.
    table = product
    id (primary key),
    link(pointing to id)
    this link can and cannot be null.its kind of parent child realtion in one table..after searching and found nothing i thought may b my design is bad so i split the product table
    table = product
    id

    table = pr_link
    prod_id ()
    link_id ()
    both are foreign keys from product table. it is one to one relation and iam unable to fix it..please help thank you..

  32. Hi,

    I have 3 tables User, Role and Permission , User to role has one to many many mapping, and role to permission has one to many mapping.
    My requirement is when i fetch user, i should get user, related roles and related permissions for the role.

  33. Hi,

    I have 3 tables User, Role and Permission , User to role has one to many many mapping, and role to permission has one to many mapping.
    My requirement is when i fetch user, i should get user, related roles and related permissions for the role.
    Fetch must be lazy. can any one help me to solve this

  34. This post was really helpful. Thanks…

  35. mappedBy – means “I am not the owner side” …

    In your article what is actually a owner side?

    Thanks for good article.

  36. This worked for me only after I set JoinColumn to not-null on Question-side like this: @JoinColumn (name = “QUESTION_ID”, nullable=false).

    Furthermore, for some reason I needed to specify column names as Java property names: “QUESTION_ID” to “question”.

  37. Great example, thanks!

  38. Thanks. This example is the easiest to understand I have come across so far.

  39. Very Good example. Really helpfull.

  40. Please note that when combining INDEX_COLUMN and DELETE_ORPHAN cascade, you MUST NOT have a database constraint on the index column. Otherwise you will get Constraint Violation Errors, since hibernate inserts first and then resets the index.

  41. Thanks for summarizing things up.
    After a long time I had to use Hibernate again and this was a perfect refresh.

    Thanks!

  42. Can any one tell me how i will create three tables with one to many mapping in hibernate annotation.
    1.discussion(disc_ID,que_ID,ans_Id)
    2.question(que_ID,question,date)
    3.answer(ans_ID,answer,date)

  43. Very helpful!

  44. Thank you, Very usefull tutorial.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s