javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session
This exception's answers are flooded over Stackoverflow but have not a single matching my problem case. I have two entities Post and User which are having ManyToMany relationship but the relationship table has two extra fields: voted_at and vote.
So, I need to have an additional entity class PostVote which would have EmbeddedId. PostVote table is the table which would hold the user who voted for the post
public class PostVote implements Serializable {
@EmbeddedId
private PostVoteId id;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("postId")
@JoinColumn(name = "post_id")
private Post post;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("userId")
@JoinColumn(name = "user_id")
private User user;
@NotNull
@CreationTimestamp
private LocalDateTime votedAt;
@NotNull
private Boolean vote = true;
public PostVote() {
}
PostVote(Post post, User user) {
this.post = post;
this.user = user;
this.id = new PostVoteId(post.getPostId(), user.getUserId());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PostVote that = (PostVote) o;
return Objects.equals(post, that.post) &&
Objects.equals(user, that.user);
}
@Override
public int hashCode() {
return Objects.hash(post, user);
}
}
The PostVoteId entity
@Embeddable
public class PostVoteId implements Serializable {
@Column(name = "post_id")
private Integer postId;
@Column(name = "user_id")
private Integer userId;
PostVoteId(Integer postId, Integer userId) {
this.postId = postId;
this.userId = userId;
}
public PostVoteId() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PostVoteId that = (PostVoteId) o;
return Objects.equals(postId, that.postId) &&
Objects.equals(userId, that.userId);
}
@Override
public int hashCode() {
return Objects.hash(postId, userId);
}
}
I am following Vlad Mihalcea article. Now, to add votes to the post, I have addVote method in Post.
public class Post implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
@Column(name = "post_id", unique = true, nullable = false)
private Integer postId;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PostVote> voters = new ArrayList<>();
public void addVote(User user){
PostVote postVote = new PostVote(this, user);
voters.add(postVote);
user.getVotedPosts().add(postVote); //problem here
}
}
The service method which is voting for the post is:
Post post = postRepository.findById(postId);
final User user = userRepository.findById(123);
post.addVote(user);
postRepository.save(post);
The above code gives the error
javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.sample.entities.PostVote#com.sample.entities.PostVoteId@4ba].
But if I remove user.getVotedPosts().add(postVote)(keep single-side bidirectional association) then it works fine.
The existing solutions didn't help. Maximum says to check the GenerationType strategy and the implementation of equals and hashcode. But in my case, both are set fine.