0

現在のプロジェクトには、他のシステムに公開できるエンティティがあります。出版物を追跡するために、エンティティには「出版物」と呼ばれる関係があります。Eclipselinkを使用しています。

このエンティティBeanには、「PreUpdate」注釈付きメソッドもあります。

他のシステムデータを最新の状態に保つことができるようにするために、PreUpdateメソッドの呼び出しの前後で実行されるアスペクトを作成しました。変更されたプロパティに応じて、いくつかのパブリケーションを削除する必要があります。すべてが完全に正常に機能しています。

私が抱えている問題は、ポータル発行コンポーネントが削除コマンドを正しく送信し、エンティティの「パブリケーション」リストからパブリケーションを削除することです。チェンジセットでは、JPAが「publications」プロパティが変更されたことに気付いたことがわかります。トランザクションがフラッシュされた後、キャッシュされたエンティティには、削除されたパブリケーションが正しくありません。残念ながら、データベースは引き続き機能し、システムを再起動するか、エンティティがDBから再度ロードされると、パブリケーションメタデータが再び存在します。

私はほとんどすべてを試しました。アスペクトのJPAChangeSetから削除されたインスタンスを取得し、entityManagerを使用して手動で削除しようとしましたが、実際には何も機能しませんでした。これらの関係エンティティを削除できないようです。現在、JDBCを使用してそれらを削除することを考えていますが、これは私の最後の手段にすぎません。

@Transactional
@Around("execution(* de.cware.services.truck.model.Truck.jpaPreUpdate(..))")
public Object truckPreUpdate(final ProceedingJoinPoint pjp) throws Throwable {
    if (alreadyExecutingMarker.get() != Boolean.TRUE) {
        alreadyExecutingMarker.set(Boolean.TRUE);

        final Truck truck = (Truck) pjp.getTarget();

        final JpaEntityManager jpaEntityManager = (JpaEntityManager) entityManager.getDelegate();
        final UnitOfWorkChangeSet changeSet = jpaEntityManager.getUnitOfWork().getCurrentChanges();
        final ObjectChangeSet objectChangeSet = changeSet.getObjectChangeSetForClone(truck);

        if (log.isDebugEnabled()) {
            log.debug("--------------------- Truck pre update check (" + truck.getId() + ") ---------------------");
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // If the truck date has changed, revoke all publication copies.
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////

        final ChangeRecord truckFreeDate = objectChangeSet.getChangesForAttributeNamed("lkwFreiDatum");
        if (truckFreeDate != null) {
            if (log.isDebugEnabled()) {
                log.debug("The date 'truckFreeDate' of truck with id '" + truck.getId() + "' has changed. " +
                        "Revoking all publications that are not marked as main applications");
            }

            for (final String portal : truck.getPublishedPortals()) {
                if (log.isDebugEnabled()) {
                    log.debug("- Revoking publications of copies to portal: " + portal);
                }

                portalService.deleteCopies(truck, portal);

                // Get any deleted portal references and use the entityManager to finally delete them.
                changeSet = jpaEntityManager.getUnitOfWork().getCurrentChanges();
                objectChangeSet = changeSet.getObjectChangeSetForClone(truck);
                final ChangeRecord publicationChanges = objectChangeSet.getChangesForAttributeNamed("publications");
                if (publicationChanges != null) {
                    if (publicationChanges instanceof CollectionChangeRecord) {
                        final CollectionChangeRecord collectionChanges =
                                (CollectionChangeRecord) publicationChanges;
                        @SuppressWarnings("unchecked")
                        final Collection<ObjectChangeSet> removedPublications =
                                (Collection<ObjectChangeSet>)
                                        collectionChanges.getRemoveObjectList().values();
                        for (final ObjectChangeSet removedPublication : removedPublications) {
                            final TruckPublication publication = (TruckPublication) ((org.eclipse.persistence.internal.sessions.ObjectChangeSet) removedPublication).getUnitOfWorkClone();
                            entityManager.remove(publication);
                        }
                    }
                }
            }
        }
    }
}

クリス

4

3 に答える 3

2

問題は、変更のセットがすでに計算されており、削除するオブジェクトのセットがすでに計算されている場合に、コミットプロセス中にPreUpdateが発生することです。

理想的には、永続化イベントではなく、アプリケーションロジックでこのようなことを実行します。

(em.remove()を使用する代わりに)イベントから直接DeleteObjectQueryを実行してみることができますが、これは機能する可能性がありますが、一般に、アプリケーションでこのロジックを実行することをお勧めします。

jpaEntityManager.getUnitOfWork()。deleteObject(object);

また、getCurrentChanges()は変更を計算します。PreUpdateイベントでは、変更はすでに計算されているため、getUnitOfWorkChangeSet()を使用できるはずです。

于 2012-10-01T13:35:47.037 に答える
0

私が見つけた唯一の解決策は、削除を実行し、JPAに新しいトランザクションを作成させるための新しいメソッドを作成することでした。これにより、changeSetが失われるため、削除されたパブリケーションを手動で確認する必要がありました。次に、そのヘルパーメソッドを呼び出すだけで、パブリケーションは正しく削除されますが、このソリューションは非常に醜いものです。

@Transactional @Around( "execution(* de.cware.services.truck.model.Truck.jpaPreUpdate(..))")public Object trackPreUpdate(final ProceedingJoinPoint pjp)throws Throwable {if(alreadyExecutingMarker.get()!= Boolean .TRUE){alreadyExecutingMarker.set(Boolean.TRUE);

    final Truck truck = (Truck) pjp.getTarget();

    final JpaEntityManager jpaEntityManager = (JpaEntityManager) entityManager.getDelegate();
    final UnitOfWorkChangeSet changeSet = jpaEntityManager.getUnitOfWork().getCurrentChanges();
    final ObjectChangeSet objectChangeSet = changeSet.getObjectChangeSetForClone(truck);

    if (log.isDebugEnabled()) {
        log.debug("--------------------- Truck pre update check (" + truck.getId() + ") ---------------------");
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // If the truck date has changed, revoke all publication copies.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////

    final ChangeRecord truckFreeDate = objectChangeSet.getChangesForAttributeNamed("lkwFreiDatum");
    if (truckFreeDate != null) {
        if (log.isDebugEnabled()) {
            log.debug("The date 'truckFreeDate' of truck with id '" + truck.getId() + "' has changed. " +
                    "Revoking all publications that are not marked as main applications");
        }

        removeCopyPublications(truck);
    }
}


@Transactional(propagation = Propagation.REQUIRES_NEW)
protected void removeCopyPublications(Truck truck) {
    // Delete all not-main-publications.
    for (final String portal : truck.getPublishedPortals()) {
        if (log.isDebugEnabled()) {
            log.debug("- Revoking publications of copies to portal: " + portal);
        }

        final Map<Integer, TruckPublication> oldPublications = new HashMap<Integer, TruckPublication>();
        for(final TruckPublication publication : truck.getPublications(portal)) {
            oldPublications.put(publication.getId(), publication);
        }

        portalService.deleteCopies(truck, portal);

        for(final TruckPublication publication : truck.getPublications(portal)) {
            oldPublications.remove(publication.getId());
        }

        for (TruckPublication removedPublication : oldPublications.values()) {
            if(!entityManager.contains(removedPublication)) {
                removedPublication = entityManager.merge(removedPublication);
            }
            entityManager.remove(removedPublication);
            entityManager.flush();
        }
    }
}

最初のバージョンが機能しないのはなぜですか?

于 2012-09-28T14:20:17.920 に答える
0

同様の問題がありました。クラスとその子があり、DBから削除された親から子を削除すると、JPA / EclipseLinkを使用してクラスParent( CascadeType.ALL )でmergeを使用して新しい子をアタッチしました。次に、子はDBではなく、永続性モーター(JPA)で作成しました。私はこれを次のように修正します:

1 - persistence.xmlファイルでshared-cache-modeNONEに設定しました

2-子を削除すると、すぐに次のように実行されます。

public void remove(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
        getEntityManager().getEntityManagerFactory().getCache().evictAll();
    }

そしてそれがすべてです。これが他の誰かに役立つことを願っています。

参照を確認してください

http://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching

于 2014-06-12T19:07:58.637 に答える