2013-04-23 57 views
0

我使用Spring/JPA/Hibernate。我有一个相当标准的Dao和Service层实现。现在对相关实体的ConstraintViolation后的Hibernate对象分离

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); } 
} 

对于这个问题,我有 -

我读它包含的数据为RelatedEntity,在数据库中创建多个记录的文件。虽然这样做,我需要设置父引用。每次插入子记录时,我都不想查找父实体。因此,我创建了所有父记录的列表并保留了父实体的地图(该集合相当小,小于10)。我循环访问数据并设置子引用并保存子进程。

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);   
    } 
} 

到目前为止,一切都很好。

我不想显式验证传入数据,而是想要使用已在实体上设置的JPA验证。所以我想在save()的前后处理constraint voilation异常,并忽略那些不验证的记录。但要继续其余的数据。

当我这样做,我得到一个异常:

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). 
     **************/ 
    } 
    } 
} 

所以看起来像父实体从当子实体抛出一个异常执着的会话分离。如果孩子在生活中没有例外,那么一切正常。

那么问题是什么,解决方案是什么?

任何帮助表示赞赏。

回答

0

我不想明确地验证传入的数据,而是要为使用在实体

这就是你的问题是已经设定JPA验证。 The documentation明确地说:

如果Session抛出异常,包括任何的SQLException,立即回滚数据库事务,调用Session.close(),丢弃该Session实例。 Session的某些方法不会使会话保持一致的状态。 Hibernate引发的异常可以视为可恢复。通过在finally块中调用close()来确保Session被关闭。

+0

在我的情况下,我认为是由Hibernate验证器pre-perist引发的异常。所以它不完全是一个SQL异常,因为在hibernate尝试持久化之前,JSR 303验证将启动。不是吗?在这种情况下,会话状态应该完全不受影响?在bean上设置所有约束并不合理,使用bean验证程序仅仅是因为您想从异常中恢复并继续操作才最终手动调用验证程序? – Anupama 2013-04-23 07:34:19

+0

该文档说“包括任何SQLException”。它不会说“排除除SQLException之外的所有异常”。对实体的JSR-303验证必须被视为数据库中的智能约束约束。您可以使用它们来创建数据库不包含垃圾,但这是最后一种手段验证,它不应该阻止您在之前验证数据,并且会强制您回滚。你当然可以自由地忽略文档所说的内容。但是如果它不起作用,那就不要抱怨。 – 2013-04-23 08:33:43