JPA与同一实体的两个单向@OneToMany关系导致重复输入

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JPA与同一实体的两个单向@OneToMany关系导致重复输入相关的知识,希望对你有一定的参考价值。

我目前正在开展一个学校项目,我们必须创建自己的“Twitter”应用程序,并且我在域对象的持久性方面遇到了一些麻烦。

我的帐户类(为便于阅读而简化):

@Entity
public class Account implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@Column(unique = true)
private String email;

@OneToMany
private final List<Account> following = new ArrayList<>();
@OneToMany(mappedBy = "tweetedBy", cascade = ALL)
private final List<Tweet> tweets = new ArrayList<>();

我的推文类(为便于阅读而简化):

@Entity
public class Tweet implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String content;

@ManyToOne
private Account tweetedBy;

@OneToMany(cascade = CascadeType.PERSIST)
@JoinTable(name = "tweet_likes")
private final List<Account> likedBy = new ArrayList<>();

@OneToMany(cascade = CascadeType.PERSIST)
@JoinTable(name = "tweet_mentions")
private final List<Account> mentions = new ArrayList<>();

持久代码(简化):

Account a1 = new Account("user1@gmail.com", "password1");
Account a2 = new Account("user2@gmail.com", "password2");
Account a3 = new Account("user3@gmail.com", "password3");

a1.addTweet("Sup mah dudes.");
a1.addTweet("yoyo");
a2.addTweet("Allo Allo #tweeting");
a2.addTweet("#testing yoyo");
a1.getTweets().get(0).addLike(a3);
a1.addFollowing(a3);

em.persist(a1);
em.persist(a2);
em.persist(a3);

我遇到的问题是likedBymentions没有被正确保留。正在生成链接器表并插入数据,但我在插入用户时不断出现重复的条目错误。我相信我正确地建立了关系(单向OneToMany),因为我不希望帐户跟踪它所提到的推文。

我尝试过的:

  • @JoinColumnlikesmentions(导致重复插入)
  • @JoinTablelikesmentions(导致重复插入)
  • @OneToManylikes只有mentions(这不会导致错误,但会为两个关系创建一个链接器表,其中任何一个都不能为null)
  • @OneToManylikes然后@joinColumnmentions nullable = true(这导致你不能在推文中提及你的情况,除非你喜欢它,这是奇怪的行为)
  • @OneToMany(cascade = CascadeType.MERGE)(导致重复插入)

Netbeans输出的重复插入错误:

Warning:   Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.qualifier): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'user6@gmail.com' for key 'EMAIL'
Error Code: 1062
Call: INSERT INTO ACCOUNT (AVATARPATH, BIO, EMAIL, ENCRYPTEDPASSWORD, LOCATION, USERNAME, USERROLE, WEBSITE) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
bind => [8 parameters bound]
Query: InsertObjectQuery(domain.Account@3c7f9d54)

我相信这个错误是因为我的JPA实现的以下流程:

  1. 帐户仍然存在
  2. 推文持续存在(因为它在账户内)
  3. 帐户持续存在(因为它在Tweet内)< - 重复条目

我期待的是:

  • 1个链接表,其中包含tweet_id (fk)account_id (fk)表示的喜欢
  • 1个链接表,其中包含tweet_id (fk)account_id (fk),表示提及

如果有人可以帮我解释注释或者解释我做错了什么,那将非常感激。

Ty提前获得任何帮助。

答案

我解决了这个问题,结果发现它是likesmentions的注释。 @JoinTable(name = "")修复了它。我认为在重新部署之前不会手动删除表导致我最初没有将此视为解决方案。

对于有类似问题的人,这是我的解决方案:

@OneToMany(cascade = CascadeType.PERSIST)
@JoinTable(name = "tweet_likes") //<--CREATES SEPERATE TABLE
private final List<Account> likedBy = new ArrayList<>();
@OneToMany(cascade = CascadeType.PERSIST)
@JoinTable(name = "tweet_mentions") //<--CREATES SEPERATE TABLE
private final List<Account> mentions = new ArrayList<>();

此外,如果我重新启动整个项目(重新启动整个glassfish / payara服务器),我会得到重复的条目错误,因为EntityManager在删除并重新创建表之前会尝试持久保存到数据库。因此,如果我在保持payara服务器在线的同时取消部署和重新部署我的项目,它仍然存在。我还没有找到解决这个问题的方法,但这是另一个问题。

以上是关于JPA与同一实体的两个单向@OneToMany关系导致重复输入的主要内容,如果未能解决你的问题,请参考以下文章

onetomany 单向与使用 jpa 的可连接设置

如何在 JPA 中定义单向 OneToMany 关系

JPA 单向一对多关联关系

java JPA中的单向OneToMany关系

OneToMany 和 ManyToMany 单向关系的区别

弹簧数据 JPA。子实体的分页