0

我使用 Spring/JPA/Hibernate。我有一个相当标准的 Dao 和 Service 层实现。

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

现在的问题,我有 -

我正在读取一个包含相关实体数据的文件,在数据库中创建了几条记录。这样做时,我需要设置父引用。我不想每次插入子记录时都查找父实体。因此,我创建了所有父记录的列表并保留了父实体的映射(这个集合相当小,不到 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() 周围的约束破坏异常并忽略不验证的记录。但想继续处理剩下的数据。

当我这样做时,我得到一个例外:

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

因此,当子实体引发持久性异常时,父实体似乎与会话分离。如果在孩子 perist 期间没有异常,一切正常。

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

任何帮助表示赞赏。

4

1 回答 1

0

我不想明确地验证传入的数据,而是想使用已经在实体上设置的 JPA 验证

这就是你的问题所在。文档明确地说:

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

于 2013-04-23T06:56:22.753 回答