JPA OneToMany和ManyToOne抛出:实体列映射中重复的列(应该使用insert =“false”update =“false”进行映射)

54

我有三个类,其中一个名称为User,而这个用户又具有其他类的实例。像这样;

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;
 }

它的工作方式就是这样,但在数据库中生成了空表格。这些表格必须包含外键。当我尝试使用 mappedByJoinColumn 注释时,失败了。我该怎么解决?

额外信息:

当我更改为;

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

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

我遇到了一个JPA错误(无法构建EntityManagerFactory):实体中的重复列映射:models.post.APost列:id(应该映射为insert =“false”update =“false”)

最终编辑:最终,我对JPA注释完全错了。 :( 当我更改

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

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

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

一切正常运作。:)


你具体是怎样失败了?你需要什么帮助,准确地说?如果第一个解决方案对你有效,为什么不坚持使用它呢? - Perception
因为JPA创建了User_APost和User_BPost表,但它没有向这些表中添加任何行。这让我感觉不对劲。 - Ömer Faruk AK
2个回答

66

我不太确定你的问题是什么(“空表”等术语的含义,还是mappedByJoinColumn没有起作用)。

我认为你在尝试进行双向关系。

首先,你需要确定哪一方“拥有”关系。Hibernate将根据该方面设置关系。例如,假设我让Post这一方拥有关系(我简化了你的示例,只为了保持重点),映射将如下所示:

(希望语法是正确的。我只是凭记忆写出来的。但是思路应该没问题)

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;
}
通过这样做,Post表将拥有一个存储关系的user_id列。Hibernate通过Post中的user获取关系(而不是在User中的posts)。如果您缺少Userposts,但却拥有Postuser,您将会注意到这种差异。

您提到mappedByJoinColumn无法正常工作。然而,我认为这实际上是正确的方法。如果您遇到问题,请告诉我们更多信息。我相信问题是由其他原因引起的。


编辑:

关于使用mappedBy的一点额外信息,因为它通常令人困惑。在mappedBy中,我们将双向关系的“属性名称”放在相反的一侧,而不是表列名。


嗨@Adrian,我不确定这个回答是否解决了他的问题。然而,我也遇到了同样的问题。即在您的解决方案中,用户只有“Post”列表,但在他的情况下,他有“APost”和“bPost”类,并且这两个帖子类都引用了用户。所以请问您能否修改您的答案,展示两个不同的类如何引用用户,并且用户与这些类之间具有ManyToOne关系?谢谢。 - WowBow
2
@WowBow,这是因为他的问题仅与双向映射方式有关,与多个一对多关系无关。我不会更新答案,因为我希望将答案与问题无关的不必要干扰保持在一边。如果您有其他问题,请随时提出另一个问题。 - Adrian Shum
2
@WowBow如果你的问题是关于如何拥有两个子类,并且想要在User中有一个方法来获取相应的aPostsbPosts,那么有很多方法。我的个人喜好是简单明了:让UserPost之间建立一对多的关系,并通过运行时过滤内部的Collection<Post>来提供getAPosts()getBPosts()的getter。你也可以像OP一样做,将APost和BPost视为完全不同的实体并维护它自己的user关系(只需使用描述的方式定义2个OneToMany关系即可)。 - Adrian Shum
谢谢您先生。这正是我在寻找的 ;) - WowBow
@JoinColumn("user_id") > 无效 >> @JoinColumn(name="user_id") - Khaled Lela
显示剩余3条评论

33

不应该使用单向的@OneToMany注解,因为:

  1. 它会生成低效的SQL语句
  2. 它会创建一个额外的表,增加数据库索引的内存占用

在你的第一个示例中,两边都拥有关联关系,这是不好的。

虽然@JoinColumn可以让@OneToMany端负责关联,但这绝对不是最好的选择。因此,总是在@OneToMany端使用mappedBy属性。

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;
}

我一直在尝试这个。但是由于明显的循环引用(用户拥有APost列表,其中包含用户,用户又拥有APost列表,...堆栈溢出错误),我不断收到堆栈溢出错误。有什么建议吗? - Roger Worrell
唯一导致堆栈溢出的方法是从子类调用父类的方法,而该方法又调用子类中的同一方法。然而,这并不是由我提出的映射所引起的。 - Vlad Mihalcea
谢谢 Vlad。我刚刚发现了 https://dev59.com/Meo6XIcBkEYKwwoYNBdQ,它似乎表明将对象序列化为 JSON 是导致问题的原因。 - Roger Worrell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接