Skip to content

Commit f842ec9

Browse files
authored
BAEL-5439: PersistentObjectException: detached entity passed to persist thrown by JPA and Hibernate (eugenp#12303)
* BAEL-5439: added code samples for article * BAEL-5439: added static import for assertj
1 parent a787ea3 commit f842ec9

File tree

4 files changed

+252
-0
lines changed

4 files changed

+252
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.baeldung.hibernate.exception.detachedentity;
2+
3+
import java.util.Properties;
4+
5+
import org.hibernate.SessionFactory;
6+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
7+
import org.hibernate.cfg.Configuration;
8+
import org.hibernate.cfg.Environment;
9+
import org.hibernate.service.ServiceRegistry;
10+
11+
import com.baeldung.hibernate.exception.detachedentity.entity.Comment;
12+
import com.baeldung.hibernate.exception.detachedentity.entity.Post;
13+
14+
public class HibernateUtil {
15+
private static SessionFactory sessionFactory;
16+
17+
public static SessionFactory getSessionFactory() {
18+
if (sessionFactory == null) {
19+
try {
20+
Configuration configuration = new Configuration();
21+
Properties settings = new Properties();
22+
settings.put(Environment.DRIVER, "org.hsqldb.jdbcDriver");
23+
settings.put(Environment.URL, "jdbc:hsqldb:mem:transient");
24+
settings.put(Environment.USER, "sa");
25+
settings.put(Environment.PASS, "");
26+
settings.put(Environment.DIALECT, "org.hibernate.dialect.HSQLDialect");
27+
settings.put(Environment.SHOW_SQL, "true");
28+
settings.put(Environment.FORMAT_SQL, "true");
29+
settings.put(Environment.USE_SQL_COMMENTS, "true");
30+
settings.put(Environment.HBM2DDL_AUTO, "update");
31+
configuration.setProperties(settings);
32+
33+
configuration.addAnnotatedClass(Comment.class);
34+
configuration.addAnnotatedClass(Post.class);
35+
36+
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties())
37+
.build();
38+
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
39+
40+
} catch (Exception e) {
41+
e.printStackTrace();
42+
}
43+
}
44+
return sessionFactory;
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.baeldung.hibernate.exception.detachedentity.entity;
2+
3+
import javax.persistence.Entity;
4+
import javax.persistence.GeneratedValue;
5+
import javax.persistence.GenerationType;
6+
import javax.persistence.Id;
7+
import javax.persistence.ManyToOne;
8+
9+
@Entity
10+
public class Comment {
11+
12+
@Id
13+
@GeneratedValue(strategy = GenerationType.IDENTITY)
14+
private Long id;
15+
16+
private String text;
17+
18+
public Comment(String text) {
19+
this.text = text;
20+
}
21+
22+
public Comment() {
23+
}
24+
25+
@ManyToOne
26+
private Post post;
27+
28+
public Long getId() {
29+
return id;
30+
}
31+
32+
public void setId(Long id) {
33+
this.id = id;
34+
}
35+
36+
public String getText() {
37+
return text;
38+
}
39+
40+
public void setText(String text) {
41+
this.text = text;
42+
}
43+
44+
public Post getPost() {
45+
return post;
46+
}
47+
48+
public void setPost(Post post) {
49+
this.post = post;
50+
}
51+
52+
@Override
53+
public String toString() {
54+
return "Comment{" + "id=" + id + ", name='" + text + '\'' + ", post=" + post + '}';
55+
}
56+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.baeldung.hibernate.exception.detachedentity.entity;
2+
3+
import javax.persistence.Entity;
4+
import javax.persistence.GeneratedValue;
5+
import javax.persistence.GenerationType;
6+
import javax.persistence.Id;
7+
8+
@Entity
9+
public class Post {
10+
11+
@Id
12+
@GeneratedValue(strategy = GenerationType.IDENTITY)
13+
private Long id;
14+
15+
private String title;
16+
17+
public Post() {
18+
}
19+
20+
public Post(String title) {
21+
this.title = title;
22+
}
23+
24+
public Long getId() {
25+
return id;
26+
}
27+
28+
public void setId(Long id) {
29+
this.id = id;
30+
}
31+
32+
public String getTitle() {
33+
return title;
34+
}
35+
36+
public void setTitle(String title) {
37+
this.title = title;
38+
}
39+
40+
@Override
41+
public String toString() {
42+
return "Post{" + "id=" + id + ", text='" + title + '\'' + '}';
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.baeldung.hibernate.exception.detachedentity;
2+
3+
import com.baeldung.hibernate.exception.detachedentity.entity.Comment;
4+
import com.baeldung.hibernate.exception.detachedentity.entity.Post;
5+
6+
import org.assertj.core.api.Assertions;
7+
import org.hibernate.Session;
8+
import org.junit.After;
9+
import org.junit.Before;
10+
import org.junit.Test;
11+
12+
import javax.persistence.PersistenceException;
13+
14+
import java.util.List;
15+
16+
import static org.assertj.core.api.Assertions.assertThat;
17+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
18+
19+
public class DetachedEntityUnitTest {
20+
21+
private static Session session;
22+
private Post detachedPost;
23+
24+
@Before
25+
public void beforeEach() {
26+
session = HibernateUtil.getSessionFactory()
27+
.openSession();
28+
session.beginTransaction();
29+
this.detachedPost = new Post("Hibernate Tutorial");
30+
session.persist(detachedPost);
31+
session.evict(detachedPost);
32+
}
33+
34+
@After
35+
public void afterEach() {
36+
clearDatabase();
37+
session.close();
38+
}
39+
40+
@Test
41+
public void givenDetachedPost_whenTryingToPersist_thenThrowException() {
42+
detachedPost.setTitle("Hibernate Tutorial for Absolute Beginners");
43+
44+
assertThatThrownBy(() -> session.persist(detachedPost))
45+
.isInstanceOf(PersistenceException.class)
46+
.hasMessageContaining("org.hibernate.PersistentObjectException: detached entity passed to persist");
47+
}
48+
49+
@Test
50+
public void givenDetachedPost_whenTryingToMerge_thenNoExceptionIsThrown() {
51+
detachedPost.setTitle("Hibernate Tutorial for Beginners");
52+
53+
session.merge(detachedPost);
54+
session.getTransaction()
55+
.commit();
56+
57+
List<Post> posts = session.createQuery("Select p from Post p", Post.class)
58+
.list();
59+
assertThat(posts).hasSize(1);
60+
assertThat(posts.get(0)
61+
.getTitle()).isEqualTo("Hibernate Tutorial for Beginners");
62+
}
63+
64+
@Test
65+
public void givenDetachedPost_whenPersistingNewCommentWithIt_thenThrowException() {
66+
Comment comment = new Comment("nice article!");
67+
comment.setPost(detachedPost);
68+
69+
session.persist(comment);
70+
session.getTransaction()
71+
.commit();
72+
73+
assertThatThrownBy(() -> session.persist(detachedPost))
74+
.isInstanceOf(PersistenceException.class)
75+
.hasMessageContaining("org.hibernate.PersistentObjectException: detached entity passed to persist");
76+
}
77+
78+
@Test
79+
public void givenDetachedPost_whenMergeAndPersistComment_thenNoExceptionIsThrown() {
80+
Comment comment = new Comment("nice article!");
81+
Post mergedPost = (Post) session.merge(detachedPost);
82+
comment.setPost(mergedPost);
83+
84+
session.persist(comment);
85+
session.getTransaction()
86+
.commit();
87+
88+
List<Comment> comments = session.createQuery("Select c from Comment c", Comment.class)
89+
.list();
90+
Comment savedComment = comments.get(0);
91+
assertThat(savedComment.getText()).isEqualTo("nice article!");
92+
assertThat(savedComment.getPost()
93+
.getTitle()).isEqualTo("Hibernate Tutorial");
94+
}
95+
96+
private void clearDatabase() {
97+
if (!session.getTransaction()
98+
.isActive()) {
99+
session.beginTransaction();
100+
}
101+
session.createQuery("DELETE FROM Comment")
102+
.executeUpdate();
103+
session.createQuery("DELETE FROM Post")
104+
.executeUpdate();
105+
}
106+
}

0 commit comments

Comments
 (0)