0

我在将现有但分离的实体设置为 ManyToOne 关系时遇到问题,Hibernate 抛出一个PersistentObjectException说法:“分离的实体传递给持久化:model.persons.Customer”。

我的用例如下:

我打开一个 JSF2 视图,它允许我通过命名 bean 和对无状态 OrderDAO EJB 的调用创建订单。在该视图中,我可以从下拉列表中选择一个客户。下拉列表使用另一个无状态 CustomerDAO EJB 填充,该 EJB 从数据库中获取客户列表。我选择客户并将客户设置为订单。当我使用无状态 OrderDAO EJB 保存订单时,会引发上述异常。

我的实体如下所示:

@Entity
public class Order extends AbstractEntity implements Serializable {

    private static final long serialVersionUID = -8061887078955032972L;

    @ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST}, optional = false)
    private Customer customer = null;

    ... 
}

@Entity
@DiscriminatorValue("customer")
public class Customer extends Person implements Serializable {

    private static final long serialVersionUID = 2788107135840578322L;

    @OneToMany(cascade=CascadeType.ALL, mappedBy="customer")
    private List<Order> orders = null;

    ...
}

涉及的代码如下所示:

@Named
@ConversationScoped
public class OrderController implements Serializable {

    private static final long serialVersionUID = -4868506512979135651L;

    @EJB
    private OrderEJB orderBean;
    private Order order;
    ...
    public Order getOrder() {
        if (order == null) {
            if (id == null) {
                order = orderBean.create();
            } else {
                order = orderBean.findById(id);
            }
        }
        return order;
    }

    public String saveOrder() {
        order = orderBean.save(order);
        return "savedOrder";
    }
}

@Stateless
public class OrderEJB extends GenericDAO<Order> {
}

public class GenericDAO<T extends AbstractEntity> {

    public T create() {
        try {
            return getClassType().newInstance();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error creating new instance of "+getClassType(), e);
        }
        return null;
    }

    public T save(T entity) {
        if (entity.getId() == null) {
            saveNew(entity);
        } else {
            entity = update(entity);
        }
        return entity;
    }

    private void saveNew(T entity) {
        em.persist(entity);
    }

    private T update(T entity) {
        return em.merge(entity);
    }

}

我使用两种不同的 EJB,一种用于订单,一种用于客户,这一事实是否存在问题?

4

1 回答 1

2

问题是您保存(持久)一个新实体,该实体引用一个分离的实体,并启用了级联以在该关系上持久(通过全部级联)。

这是不受支持的组合。

JPA 希望这种关系中的整个链都是新对象。如果一个人已经有一个持久的身份(附加的或分离的),它就行不通了。

有两种解决方案:

删除从 Customer 到 Order 的关系上的级联。客户仍将获得对现有订单的引用,但 JPA 不会尝试保留订单本身。您将失去一次性为新客户保留新订单的能力,但如果这种情况永远不会发生,那么这可能是一个很好的解决方案。

第二种解决方案有点反直觉,但确实有效;为具有现有订单的新客户调用 em.merge() 而不是 em.persist()。

Merge 实际上具有“saveOrUpdate”语义,因此无需关心对象是否为新对象即可进行保存。

于 2012-09-04T08:33:54.613 回答