3

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

一个类别和一个问题。所以每个类别都有一个问题列表,每个问题都是一个类别的一部分(OnetoMany 关系)。我通过两个实体中的设置/添加方法管理双向关系:

问题 :

    @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 一次。该错误意味着您已经在传入的那个 Question 对象上调用了 persist ,但是您在另一个事务中这样做了。如果要将 Question 对象重新附加到持久性上下文,则需要调用 merge 或从数据库重新加载它。

于 2013-03-11T11:48:15.670 回答
0

在 persist 或 merge 之前你需要做的是在每个 Question 中设置 Category 引用。

于 2013-03-11T08:56:39.117 回答
0

[注:这可能不是直接的答案,只是一些观察]

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

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

  3. 你有什么cascade=MERGE/cascade=PERSISTcascade=ALL你的关系。

  4. 可能,您可以Category在当前事务中再次按 id 获取并在question持久之前将其设置。

从文档:

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

  • 双向关系的反面必须通过使用 @OneToOne、@OneToMany 或 @ManyToMany 注释的 mappedBy 元素引用其拥有方。mappedBy 元素指定实体中作为关系所有者的属性或字段。
  • 多对一双向关系的多方不得定义 mappedBy 元素。多方始终是关系的拥有方。
  • 对于一对一的双向关系,拥有方对应于包含相应外键的一方。
  • 对于多对多双向关系,任何一方都可能是拥有方。
于 2013-03-11T09:51:21.563 回答