我目前正在做一个学校项目,我们必须创建自己的“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);
我遇到的问题是 likedBy
和 mentions
没有正确保存。正在生成链接器表并插入数据,但我在用户插入时不断收到重复输入错误。我相信我正确地建模了这种关系(单向 OneToMany),因为我不希望帐户跟踪其中提到的推文。
我尝试过的:
@JoinColumn
likes
和mentions
(导致重复插入)@JoinTable
likes
和mentions
(导致重复插入)- 只有
@OneToMany
用于likes
和mentions
(这不会导致错误,但会为两种关系创建 1 个链接器表,其中不能为空) @OneToMany
表示likes
,然后@joinColumn
表示mentions
,其中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 实现的以下流程造成的:
- 帐户保留
- 推文保留(因为它在帐户内)
- 帐户保留(因为它在 Tweet 中)<-- 重复条目
我的期望:
- 1 个带有
tweet_id (fk)
和account_id (fk)
表示喜欢的链接器表 - 1 个带有
tweet_id (fk)
和account_id (fk)
表示提及的链接器表
如果有人可以帮助我进行注释或解释我做错了什么,我们将不胜感激。
如有任何帮助,请提前联系。
最佳答案
问题解决了,原来是likes
和mentions
处的注解。 @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 服务器在线,它仍然很好。我还没有找到解决这个问题的方法,但那是另一个问题。
关于java - JPA 与同一实体的两个单向@OneToMany 关系导致重复条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49012996/