JPA 与同一实体的两个单向@OneToMany 关系导致重复条目
JPA two unidirectional @OneToMany relationships to the same entity resulting in duplicate entry
我目前正在做一个学校项目,我们必须创建自己的 'Twitter' 应用程序,但我在域对象的持久性方面遇到了一些麻烦。
我的帐户class(为了便于阅读而进行了简化):
@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<>();
我的推文class(为便于阅读而简化):
@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
没有正确保存。正在生成链接器 table 并插入数据,但我在用户插入时不断收到重复输入错误。我相信我正确地为关系建模(单向 OneToMany),因为我不希望帐户跟踪其中提到的推文。
我尝试过的:
@JoinColumn
对于 likes
和 mentions
(导致重复插入)
@JoinTable
对于 likes
和 mentions
(导致重复插入)
- 仅
@OneToMany
用于 likes
和 mentions
(这不会导致错误,但会为两种关系创建 1 个链接器 table,其中任何一个都不能为空)
@OneToMany
for likes
然后 @joinColumn
for mentions
where 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 个链接器 table 带有一个
tweet_id (fk)
和一个 account_id (fk)
表示喜欢
- 1 个链接器 table 带有一个
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 服务器在线,它仍然很好。我还没有找到解决这个问题的方法,但那是另一个问题。
我目前正在做一个学校项目,我们必须创建自己的 'Twitter' 应用程序,但我在域对象的持久性方面遇到了一些麻烦。
我的帐户class(为了便于阅读而进行了简化):
@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<>();
我的推文class(为便于阅读而简化):
@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
没有正确保存。正在生成链接器 table 并插入数据,但我在用户插入时不断收到重复输入错误。我相信我正确地为关系建模(单向 OneToMany),因为我不希望帐户跟踪其中提到的推文。
我尝试过的:
@JoinColumn
对于likes
和mentions
(导致重复插入)@JoinTable
对于likes
和mentions
(导致重复插入)- 仅
@OneToMany
用于likes
和mentions
(这不会导致错误,但会为两种关系创建 1 个链接器 table,其中任何一个都不能为空) @OneToMany
forlikes
然后@joinColumn
formentions
wherenullable = 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 个链接器 table 带有一个
tweet_id (fk)
和一个account_id (fk)
表示喜欢 - 1 个链接器 table 带有一个
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 服务器在线,它仍然很好。我还没有找到解决这个问题的方法,但那是另一个问题。