I'm currently working on a school project where we have to create our own 'Twitter' application and I'm having some trouble with the persistence of the domain objects.
My Account class (simplified for readability):
@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<>();
My Tweet class (simplified for readability):
@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<>();
The persist code (simplified):
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);
The problem I'm having is that the likedBy
and mentions
aren't being persisted correctly. The linker tables are being generated and the data gets inserted but I keep getting a duplicate entry error on the insert of a user. I believe I modeled the relationship correctly (unidirectional OneToMany), because I don't want an Account to keep track of Tweets it was mentioned in.
What I have tried:
@JoinColumn
for both likes
and mentions
(results in duplicate insert)@JoinTable
for both likes
and mentions
(results in duplicate insert)@OneToMany
for both likes
and mentions
(this does not result in an error but creates 1 linker table for both relationships where either cannot be null)@OneToMany
for likes
and then @joinColumn
for mentions
where nullable = true
(this results in the scenario where u cannot be mentioned in a tweet unless you like it, which is odd behaviour)@OneToMany(cascade = CascadeType.MERGE)
(results in duplicate insert)Netbeans output of duplicate insert error:
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)
I believe this error occurs because of the folowing flow of my JPA imlementation:
What I expect:
tweet_id (fk)
and an account_id (fk)
representing likestweet_id (fk)
and an account_id (fk)
representing mentionsIf someone could help me with the annotations or explain what else I'm doing wrong that would be very much appreciated.
Ty in advance for any help.
I solved the problem, it turns out it was the annotations at the likes
and mentions
. @JoinTable(name = "")
fixed it. I think not dropping the tables manually before redeploying caused that I did not see this as the solution at first.
for anyone with a similar problem, this is my solution:
@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<>();
Also, apearently if I restart my entire project (restart the entire glassfish/payara server) I get the duplicate entry error because the EntityManager tries to persist to the database before the tables have been dropped and recreated. So if I just undeploy and redeploy my project while keeping the payara server online, it persists just fine. I have not yet been able to find a solution to this problem but thats for another question.