Darth Blue Ray
Darth Blue Ray

Reputation: 9745

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

I have 2 entities in a JPA project:

A category and a question. so each Category will have a list of questions and each question will be part of a category (OnetoMany relation). I manage the bi-directional relationship through the set/add methodes in both entities :

Question :

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

Category :

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

 }

I first create a category.

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

I add this to the db through my repository (added in a similar way as the question addOrUpdate as below)

After that I create an question

Question question1 = new Question();

I set the category of the question to category1

question.setCategory = category1;

After this I also try to persist the question to the db by calling the addOrUpdate method below. I then get an error :

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

I use a repository method like :

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

Any suggestion would be more then welcome.

Upvotes: 3

Views: 5546

Answers (3)

Pace
Pace

Reputation: 43957

So you're only allowed to call persist once on an entity. That error means that you've already called persist on that Question object that is being passed in, but you did so in another transaction. If you want to reattach the Question object to the persistence context you need to call merge or reload it from the database.

Upvotes: 1

Nayan Wadekar
Nayan Wadekar

Reputation: 11622

[Note: This may be not the direct answer, just few observations]

  1. It's definitely isn't a good practice to initialize EntityManagerFactory with each method invocation. Instead, it should be created once probably during application startup.

  2. You are passing Category, which is part of another persistence context to addOrUpdate in which it isn't in managed state.

  3. What do you have cascade=MERGE/cascade=PERSIST or cascade=ALL on your relationship.

  4. Probably, you can fetch Category by id again in the current thransaction & set it in question before persisting.

From Documentation :

Bidirectional relationships must follow these rules.

  • The inverse side of a bidirectional relationship must refer to its owning side by using the mappedBy element of the @OneToOne, @OneToMany, or @ManyToMany annotation. The mappedBy element designates the property or field in the entity that is the owner of the relationship.
  • The many side of many-to-one bidirectional relationships must not define the mappedBy element. The many side is always the owning side of the relationship.
  • For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key.
  • For many-to-many bidirectional relationships, either side may be the owning side.

Upvotes: 0

PSR
PSR

Reputation: 40358

What you have to do before persist or merge is to set the Category reference in each Question .

Upvotes: 0

Related Questions