0

既存のデタッチされたエンティティをManyToOneリレーションに設定する際に問題が発生しました。Hibernateは次のようにPersistentObjectException言います:'デタッチされたエンティティがpersistに渡されました:model.persons.Customer'。

私のユースケースは次のとおりです。

JSF2ビューを開いて、NamedBeanとステートレスOrderDAOEJBの呼び出しを介して注文を作成できます。そのビューで、ドロップダウンリストから顧客を選択できます。ドロップダウンリストは、データベースから顧客のリストをフェッチする別のステートレスCustomerDAOEJJを使用して入力されます。顧客を選択すると、顧客は注文に設定されます。ステートレスOrderDAOEJJを使用して注文を保存すると、上記の例外がスローされます。

私のエンティティは次のようになります。

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

}

注文用と顧客用の2つの異なるEJBを使用しているという事実は問題ですか?

4

1 に答える 1

2

問題は、その関係で(すべてのカスケードを介して)永続化するためにカスケードが有効になっているデタッチされたエンティティへの参照を使用して、新しいエンティティを保存(永続化)することです。

これはサポートされていない組み合わせです。

JPAは、この関係のチェーン全体を新しいオブジェクトにすることを望んでいます。永続的なID(接続または切断)がすでにある場合は、機能しません。

2つの解決策があります:

顧客から注文への関係のカスケードを削除します。顧客は引き続き既存の注文への参照を取得しますが、JPAは注文自体を永続化しようとはしません。新しい注文で新しい顧客を一度に維持する機能が失われますが、これが決して起こらない場合は、これは良い解決策になる可能性があります。

2番目の解決策は少し直感的ではありませんが、機能します。既存の注文を持つ新しい顧客に対しては、em.persist()の代わりにem.merge()を呼び出します。

Mergeは実際には「saveOrUpdate」セマンティクスを持っているため、オブジェクトが新しいかどうかを気にせずに保存を実行します。

于 2012-09-04T08:33:54.613 に答える