Spring - hibernate: detached entity passed to persist
I have the following Object:
public class Constraint {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
int id;
String name;
String description;
String path;
int level;
@ManyToOne
@JoinColumn(name="parent_id")
Constraint parent;
@OneToMany
@JoinColumn(name="parent_id")
Set<Constraint> children;
@ManyToOne
@JoinColumn(name="type_id")
ConstraintType type; }
As you see this table represents a tree structure. Having the functions:
public List<Constraint> getAllDescendantsOfConstraint(Integer id) {
StringBuilder sb = new StringBuilder();
sb.append("WITH RECURSIVE tree as ");
sb.append("( ");
sb.append(" select * from constraints where id = :id ");
sb.append(" union all ");
sb.append(" select a.* from constraints a, tree b where a.parent_id = b.id ");
sb.append(") ");
sb.append("select * from tree where id <> :id ");
Query q = entityManager.createNativeQuery(sb.toString(), Constraint.class);
q.setParameter("id", id);
return (List<Constraint>) q.getResultList();
}
@Transactional
public void setupPaths() {
Query q = entityManager.createQuery("from Constraint", Constraint.class);
@SuppressWarnings("unchecked")
List<开发者_开发百科;Constraint> constraints = (List<Constraint>) q.getResultList();
for(Constraint c : constraints) {
List<Constraint> descendants = getAllDescendantsOfConstraint(c.getId());
for(Constraint d : descendants) {
String tpath;
if((tpath = d.getPath()) == null || d.getPath().equals(""))
tpath = String.valueOf(c.getId());
else
tpath = d.getPath() + "." + String.valueOf(c.getId());
d.setPath(tpath);
entityManager.persist(d);
}
}
}
If a call setupPaths i get a "detached entity passed to persist exception".
If instead of entityManager.persist(d);
i do :
d = entityManager.merge(d);
d.setPath(tpath);
Nothing happens (the data is not saved in the db). If a call flush, i get detached entity passed to persist exception as well. I suspect it has something to do with me not eagerly loading the parent or children?
edit: After further testing since the above seems really fishy, it seems that every entity i get from entityManager, no matter how i get it (either with em.find(MyObject.class,id or any kind of queries) it is detached right after fetching! I see that from calling
em.contains(myObject)
which always returns false. The problem is that i use the exact same setup on other spring projects with the same database server and it's wroking fine.
After (finally) turning debug info for Hibernate on i saw that the EntityManager was closing the session right after fetch which was wrong since i was using @Transactional annotation. Finally it seems that was a problem with STS (springsource toolsuite) and spring configuration, particularly:
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
This supposedly witht the correct maven setup
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.3.1</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>compile</id>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
<verbose>false</verbose>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<outxml>true</outxml>
<source>${java-version}</source>
<target>${java-version}</target>
</configuration>
</plugin>
should take care of compile-time weaving but something went wrong. I was using plugin 1.2, when i changed that to 1.3.1 it magically worked.
精彩评论