2013-03-10 3 views
3

У меня есть 2 объектов в проекте JPA:javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: ошибка

категорию и вопрос. поэтому каждая категория будет иметь список вопросов, и каждый вопрос будет частью категории (отношение OnetoMany). Я управляю отношения двунаправленную через набор/добавить methodes в обоих образованиях:

Вопрос:

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

Я установить категорию вопроса к категории1

question.setCategory = category1; 

После этого я также пытаюсь сохранить вопрос до t он db, вызвав метод addOrUpdate ниже. Затем я получаю сообщение об ошибке:

....: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; 
} 

Любое предложение было бы более прием.

+0

Вы когда-нибудь называли persist/merge по категории? – Pace

+0

Вы устанавливаете значения для 'tempQuestion', но объединяете' question' или это просто опечатка. –

+0

@Pace Не напрямую, я ставлю только отношение к категории. Но я понимаю, что также добавляю этот вопрос к списку в категории. Но я использую CascadeType.ALL для лица, у которого есть отношение. Поэтому я верю, что он это сделает. –

ответ

1

Таким образом, вы можете разрешать только один раз на объекте. Эта ошибка означает, что вы уже вызвали сохранение этого объекта Question, который передается, но вы сделали это в другой транзакции. Если вы хотите повторно привязать объект Question к контексту персистентности, вам нужно вызвать merge или перезагрузить его из базы данных.

+0

Сначала создаю категорию и сохраняю ее в db (persist). После этого я создаю вопрос, и задаю вопрос .setCategory к категории, которую я создал. Затем я пытаюсь сохранить этот новый вопрос в db (со ссылкой на уже прошедшую категорию). Я сохраняю оба конца отношений в правильном состоянии. Я считаю, что это «обычный» способ для работы с этими реалиями. Вы создаете один объект, который необходим в другом, и выберите его, прежде чем я создам другой. –

+1

А, но у вас есть постоянный каскад по вашему вопросу. Это означает, что он идет, и вызовы сохраняются в категории, которая уже сохранялось, таким образом, сообщение. Удалите каскад persist из поля категории объекта Question. – Pace

+0

Это похоже на трюк. Каскад, который мне нужно ввести? Я изменил его на Cascade.M ERGE, но мне нужно оценить, нормально ли это –

0

Что нужно сделать, прежде чем упорство или слияние - установить ссылку категории в каждом Вопросе.

+0

Но я делаю это, когда пишу: question.setCategory = category1; ? –

+0

Я добавил двунаправленную настройку к сообщению. Я верю, что делаю это правильно –

0

[Примечание: Это может быть не прямой ответ, только несколько замечаний]

  1. Это, безусловно, не является хорошей практикой для инициализации EntityManagerFactory с каждым вызовом метода. Вместо этого он должен быть создан один раз, вероятно, во время запуска приложения.

  2. Вы передаете Category, который является частью другого контекста персистентности до addOrUpdate, в котором он не находится в управляемом состоянии.

  3. У вас есть cascade=MERGE/cascade=PERSIST или cascade=ALL на ваши отношения.

  4. Возможно, вы можете получить Category по идентификатору снова в текущем thransaction & установить его в question перед тем сохраняющиеся.

Из документации:

двунаправленного отношения должны следовать этим правилам.

  • обратная сторона двунаправленного отношения должны относиться к его стороне, владеющей с помощью элемента mappedBy из @OneToOne, @OneToMany или @ManyToMany аннотации. Элемент mappedBy обозначает свойство или поле в объекте, который является владельцем отношения .
  • Многие стороны двунаправленных отношений «один-на-один» не должны определять элемент mappedBy. Многосторонняя сторона всегда принадлежит стороне отношений.
  • Для взаимно-двунаправленных отношений сторона-обладательница соответствует стороне, которая содержит соответствующий внешний ключ.
  • Для двухсторонних двунаправленных отношений любая сторона может быть стороной-обладателем.
+0

У меня есть Cascade = CascadeType.ALL в моих отношениях (см. Отношение в верхней части моего вопроса). Я считаю, что я следовал правилам этого отношения. Как получить идентификатор снова, если вы видите мой метод addOrUpdate? –

+0

@DarthBlueRay Это похоже на то, что вы сделали, чтобы получить «tempQuestion» через EntityManager, что-то вроде 'em.find (Question.class, category.getId())' и затем установите его в 'question'. Можете попробовать свой текущий код с распространением одной транзакции. Создайте категорию, а затем продолжайте ее, затем установите ее под вопросом и сохраняйте. Могут быть изменены операции persist/merge. –

+0

Я изменил код: tempCategory = em.find (. Category.class, \t \t \t \t \t \t question.getCategory() GetId()); \t \t \t \t tempFeedbackVraag.setCategory (tempCategory); Если это то, что вы имеете в виду. У меня такая же ошибка .... –

Смежные вопросы