I use Spring / JPA / Hibernate. I have a fairly standard Dao and Service layer implementations.
class GenericDao<T> {
public save(T entity) {
if (!entity.isIdSet()) {
getEntityManager().persist(entity);
}
// other cases are update,
// so a transactional service method will suffice
// we dont need to do anything
}
}
class ParentEntity {
// Nothing special here, just an entity with auto-generated PK, if that matters
}
class RelatedEntity {
// Fairly standard many-to-one relation
@Column(name = "parent_id",nullable = false,insertable = false,updatable = false)
public Integer getParentId() {
return parentId;
}
@NotNull
@JoinColumn(name = "parent_id", nullable = false)
@ManyToOne(cascade = {PERSIST, MERGE}, fetch = LAZY)
public ParentEntity getParent() {
return parent;
}
}
class Repository<T> { // There is an implementation of this for both entities above
@Transactional
public void save(T entity) { getDao().save(entity); }
}
Now for the problem, I am having -
I am reading a file which contains data for the RelatedEntity, creating several records in the database. While doing that I need to set the parent reference. I dont want to lookup the parent entity everytime I insert a child record. So I create a list of all parent records and keep a map of parent entities (this set is fairly small, less than 10). I loop through the data and set the parent reference in the child and save the child.
public void getParentList {
List parentList = parentRepository.find();
// create a map with the list items for easy lookup on name
}
public void importData() {
for (line : file) {
RelatedEntity re = new RelatedEntity();
re.setParent(map.get(line.parentName)); // The refered object is got once in getParentList
// lookup the map for the parent
// set all properties of re here
childRepository.save(re);
}
}
So far, all is well.
I did not want to validate the incoming data explicitly, instead want to use JPA validation that is already set on the entity. So I want to handle constraint voilation exception around save() and ignore the records that do not validate. But want to continue with the rest of the data.
When I do that, I get a an exception :
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.myads.domain.ParentEntity
public void importData() {
for (line : file) {
RelatedEntity re = new RelatedEntity();
// lookup the map for the parent
// set all properties of re here
try {
childRepository.save(re);
} catch (CVE cve) {
// log the record that failed validation
/*************
// Note: If I land here on line(x), I get PersistenceException on save for the
// next iteration(x+1).
**************/
}
}
}
So looks like the parent entity is detached from the session when a child entity throws a persistence exception. If there are no exceptions during perist of the child, everything works fine.
So what is the problem and what is the solution?
Any help is appreciated.