3

JPA プロジェクトに 2 つのエンティティがあります。

カテゴリと質問。したがって、各カテゴリには質問のリストがあり、各質問はカテゴリの一部になります (1 対多の関係)。両方のエンティティで 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 メソッドを呼び出して、質問をデータベースに永続化しようとします。その後、エラーが発生します:

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

どんな提案でも大歓迎です。

4

3 に答える 3

1

したがって、エンティティでpersistを呼び出すことができるのは1回だけです。このエラーは、渡されているQuestionオブジェクトでpersistをすでに呼び出しているが、別のトランザクションで呼び出したことを意味します。Questionオブジェクトを永続コンテキストに再アタッチする場合は、mergeを呼び出すか、データベースからリロードする必要があります。

于 2013-03-11T11:48:15.670 に答える
0

永続化またはマージする前に行う必要があるのは、各質問にカテゴリ参照を設定することです。

于 2013-03-11T08:56:39.117 に答える
0

[注: これは直接的な答えではないかもしれません。いくつかの観察結果です]

  1. EntityManagerFactoryメソッドの呼び出しごとに初期化することは、絶対にお勧めできません。代わりに、おそらくアプリケーションの起動時に一度作成する必要があります。

  2. 管理状態にないCategory別の永続化コンテキストの一部であるを渡しています。addOrUpdate

  3. あなたは何を持っていますかcascade=MERGE/cascade=PERSISTまたはcascade=ALLあなたの関係について.

  4. おそらく、Category現在の thransaction で id で再度取得し、question永続化する前に設定できます。

ドキュメントから:

双方向の関係は、これらの規則に従う必要があります。

  • 双方向リレーションシップの反対側は、@OneToOne、@OneToMany、または @ManyToMany アノテーションの MappedBy 要素を使用して、その所有側を参照する必要があります。MappedBy 要素は、関係の所有者であるエンティティ内のプロパティまたはフィールドを指定します。
  • 多対一の双方向関係の多側では、mappedBy 要素を定義してはなりません。多側は常に関係の所有側です。
  • 1 対 1 の双方向関係の場合、所有側は、対応する外部キーを含む側に対応します。
  • 多対多の双方向関係の場合、いずれかの側が所有側になる場合があります。
于 2013-03-11T09:51:21.563 に答える