JPA OneToMany and ManyToOne throw: Repeated column in mapping for entity column (should be mapped with insert="false" update="false")
Asked Answered
P

2

54

I have three classes one of the names is User and this user has other classes instances. Like this;

public class User{
    @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
    public List<APost> aPosts;

    @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
    public List<BPost> bPosts;
}




   public class BPost extends Post {
    
    @ManyToOne(fetch=FetchType.LAZY)    
    public User user;
 }
    
    public class APost extends Post {
    
     @ManyToOne(fetch=FetchType.LAZY) 
     public User user;
 }

it's working like this but generates empty tables in DB. Which have to contain foreign keys. When I tried to use mappedBy and JoinColumn annotations I got failed. How can I resolve this?

Extra information:

When I changed with;

 @ManyToOne(fetch=FetchType.LAZY)
 @JoinColumn(name="id")
 public User user;

and

 @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="id")
 public List<APost> aPosts;

I'm getting

A JPA error occurred (Unable to build EntityManagerFactory): Repeated column in mapping for entity: models.post.APost column: id (should be mapped with insert="false" update="false")

Final Edit: Finally, I was totally wrong about JPA annotations. :( When I change

@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="id")

to

@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")

and

@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_id")

everything works ok. :)

Pasteup answered 11/12, 2012 at 0:45 Comment(2)
How exactly did you fail? What are you seeking help with, precisely? And if the first solution worked for you why not stick with it?Degraw
because jpa creates User_APost and User_BPost tables but it's not adding any row to this tables. And it feels me wrong.Wateriness
I
33

You should never use the unidirectional @OneToMany annotation because:

  1. It generates inefficient SQL statements
  2. It creates an extra table which increases the memory footprint of your DB indexes

Now, in your first example, both sides are owning the association, and this is bad.

While the @JoinColumn would let the @OneToMany side in charge of the association, it's definitely not the best choice. Therefore, always use the mappedBy attribute on the @OneToMany side.

public class User{
    @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
    public List<APost> aPosts;

    @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
    public List<BPost> bPosts;
}

public class BPost extends Post {

    @ManyToOne(fetch=FetchType.LAZY)    
    public User user;
}

public class APost extends Post {

     @ManyToOne(fetch=FetchType.LAZY) 
     public User user;
}
Instrumentalism answered 10/8, 2017 at 12:8 Comment(3)
I have been trying this. However, I keep getting a stack overflow due to the obvious circular reference (User has list of APost, which has the user, which has a list of APost, ... Stack Overflow error). Any pointers on that?Cornelia
The only way to get a StackOverflow is by calling from the child a method from the parent which in turn calls the same method in the child.However, that's not due to the mapping I proposed you.Instrumentalism
Thanks Vlad. I just found #17446157 which seems to indicate it's the serialization of the object to JSON that is causing the problem.Cornelia
O
66

I am not really sure about your question (the meaning of "empty table" etc, or how mappedBy and JoinColumn were not working).

I think you were trying to do a bi-directional relationships.

First, you need to decide which side "owns" the relationship. Hibernate is going to setup the relationship base on that side. For example, assume I make the Post side own the relationship (I am simplifying your example, just to keep things in point), the mapping will look like:

(Wish the syntax is correct. I am writing them just by memory. However the idea should be fine)

public class User{
    @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
    private List<Post> posts;
}


public class Post {
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="user_id")
    private User user;
}

By doing so, the table for Post will have a column user_id which store the relationship. Hibernate is getting the relationship by the user in Post (Instead of posts in User. You will notice the difference if you have Post's user but missing User's posts).

You have mentioned mappedBy and JoinColumn is not working. However, I believe this is in fact the correct way. Please tell if this approach is not working for you, and give us a bit more info on the problem. I believe the problem is due to something else.


Edit:

Just a bit extra information on the use of mappedBy as it is usually confusing at first. In mappedBy, we put the "property name" in the opposite side of the bidirectional relationship, not table column name.

Ordonnance answered 11/12, 2012 at 1:8 Comment(7)
i have add extra information to post adrian. It contains errors when i changed my annotations with your suggestions.Wateriness
sorry bro, i couldn't understand your answer at first. :)Wateriness
Hi @Adrian, I am not sure how this answered his question. However, I have the same problem. i.e In your solution User has only list of "Post" but in his case he has class "APost" and "bPost" and both of this post classes refer to User. So can please modify your answer by showing to different classes referencing User and User having ManyToOne r/s with those classes? Thanks.Tarango
@Tarango it is simply because his problem is solely related to the way to do bi-directional mapping, and have nothing to do with multiple one-to-many relationship. Won't update the answer as I want to keep the answer away from unnecessary distraction unrelated to problem. If you have other problem, feel free to raise it as another question.Ordonnance
@Tarango if your question is about how to have 2 sub-class, and you want to have method in User to get corresponding aPosts and bPosts, there are lots of ways. My personal preference is to make it simple: have User having one-to-many relationship to Post, and provide getters for getAPosts() and getBPosts() simply by run-time filtering the internal Collection<Post>. You can also do it like OP, while treating APost and BPost as totally different entity and maintain its own user relationship (There is nothing more than defining 2 OneToMany relationship using described way).Ordonnance
@JoinColumn("user_id") > Not working >> @JoinColumn(name="user_id")Fulvi
@KhaledLela thanks for pointing that out. Fixing it. I think should be easy to figure out though :)Ordonnance
I
33

You should never use the unidirectional @OneToMany annotation because:

  1. It generates inefficient SQL statements
  2. It creates an extra table which increases the memory footprint of your DB indexes

Now, in your first example, both sides are owning the association, and this is bad.

While the @JoinColumn would let the @OneToMany side in charge of the association, it's definitely not the best choice. Therefore, always use the mappedBy attribute on the @OneToMany side.

public class User{
    @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
    public List<APost> aPosts;

    @OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="user")
    public List<BPost> bPosts;
}

public class BPost extends Post {

    @ManyToOne(fetch=FetchType.LAZY)    
    public User user;
}

public class APost extends Post {

     @ManyToOne(fetch=FetchType.LAZY) 
     public User user;
}
Instrumentalism answered 10/8, 2017 at 12:8 Comment(3)
I have been trying this. However, I keep getting a stack overflow due to the obvious circular reference (User has list of APost, which has the user, which has a list of APost, ... Stack Overflow error). Any pointers on that?Cornelia
The only way to get a StackOverflow is by calling from the child a method from the parent which in turn calls the same method in the child.However, that's not due to the mapping I proposed you.Instrumentalism
Thanks Vlad. I just found #17446157 which seems to indicate it's the serialization of the object to JSON that is causing the problem.Cornelia

© 2022 - 2024 — McMap. All rights reserved.