javax.persistence.PersistenceException:org.hibernate.PersistentObjectException:error

时间:2013-03-10 23:38:16

标签: java hibernate jpa entitymanager

我在JPA项目中有2个实体:

类别和问题。所以每个类别都会有一个问题列表,每个问题都将成为一个类别的一部分(OnetoMany关系)。我通过两个实体中的set / add方法管理双向关系:

问题:

    @ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "Qcategory")
private Category category;

public void setCategory(Category category) {
 this.category = category;

 if (category != null && !category.getQuestions().contains(this)) {
 category.addQuestion(this);
 }
 }

类别:

@OneToMany(cascade = { CascadeType.ALL }, mappedBy = "category")
private List<Question> questions= new ArrayList<Question>();


 public void addQuestion(Question question) {
 this.questions.add(question);

 if (question.getCategory() != this) {
 question.setCategory(this);
 }

 }

我首先创建一个类别。

Category category1 = new Category();
category1.setName = "exampleCategory";

我通过我的存储库将其添加到数据库中(以类似于addOrUpdate的方式添加,如下所示)

之后我创建了一个问题

Question question1 = new Question();

我将问题的类别设置为category1

question.setCategory = category1;

在此之后,我还尝试通过调用下面的addOrUpdate方法将问题持久化到db。然后我收到一个错误:

....:javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: jpa.entities.Category

我使用的存储库方法如下:

@Override
public boolean addOrUpdate(Question question) {
    EntityManagerFactory emf = JPARepositoryFactory
            .getEntityManagerFactory();
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();

    Question tempQuestion = null;
    try {
        if (question.getId() != null) {
            tempQuestion = em.find(Question.class,
                    question.getId());
        }

        if (tempQuestion == null) {
            em.persist(question);
        } else {

            tempQuestion .setCategory(question.getCategory());
            ... (other setters)
            tempQuestion = em.merge(question);
        }
    } catch (Exception e) {
        ....logging...      }
    tx.commit();
    em.close();
    emf.close();
    return true;
}

任何建议都会受到欢迎。

3 个答案:

答案 0 :(得分:1)

因此,您只能在实体上调用一次persist。该错误意味着您已经在传入的Question对象上调用了persist,但是您在另一个事务中执行了此操作。如果要将Question对象重新附加到持久性上下文,则需要调用merge或从数据库重新加载它。

答案 1 :(得分:0)

在持久或合并之前,您需要做的是在每个问题中设置类别引用。

答案 2 :(得分:0)

[注意:这可能不是直接答案,只是几点观察]

  1. 使用每个方法调用初始化EntityManagerFactory绝对不是一个好习惯。相反,应该在应用程序启动期间创建一次。

  2. 您正在传递Category,这是另一个持久性上下文的一部分,而addOrUpdate处于托管状态。

  3. 您对自己的关系有cascade=MERGE / cascade=PERSISTcascade=ALL

  4. 也许,你可以在当前的thransaction&amp;中再次通过id获取Category。在坚持之前将其设置在question

  5. 来自文档:

      

    双向关系必须遵循这些规则。

         
        
    • 双向关系的反面必须通过使用@OneToOne的mappedBy元素引用其拥有方,   @OneToMany或@ManyToMany注释。 mappedBy元素指定   作为所有者的实体中的财产或字段   关系。
    •   
    • 多对一双向关系的许多方面不得定义mappedBy元素。许多方面始终是拥有方   关系。
    •   
    • 对于一对一的双向关系,拥有方对应于包含相应外键的一侧。
    •   
    • 对于多对多双向关系,任何一方都可能是拥有方。
    •