0

在我当前的项目中,我有一个可以发布到其他系统的实体。为了跟踪出版物,实体有一个称为“出版物”的关系。我正在使用 Eclipselink。

这个实体 bean 也有一个“PreUpdate”注解的方法。

为了能够使其他系统数据保持最新,我创建了一个围绕 PreUpdate 方法的调用执行的 Aspect。根据更改了哪些属性,我需要删除一些出版物。一切正常。

我遇到的问题是门户发布组件正确发送删除命令并从实体“发布”列表中删除发布。我什至可以在变更集中看到 JPA 注意到“publications”属性发生了变化。刷新事务后,缓存实体正确地不再具有已删除的发布。不幸的是,数据库仍然存在,当系统重新启动或再次从数据库加载实体时,发布元数据再次出现。

我几乎什么都试过了。我什至设法从 Aspect 中的 JPA ChangeSet 中获取已删除的实例,并尝试使用 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,此时已经计算了更改集,并且已经计算了要删除的对象集。

理想情况下,您将在应用程序逻辑中执行类似的操作,而不是通过持久性事件。

您可以尝试直接从您的事件中执行 DeleteObjectQuery(而不是使用 em.remove()),这可能有效,但通常最好在您的应用程序中执行此逻辑。

jpaEntityManager.getUnitOfWork().deleteObject(object);

另请注意,getCurrentChanges() 计算更改,在 PreUpdate 事件中已经计算更改,因此您应该能够使用 getUnitOfWorkChangeSet()。

于 2012-10-01T13:35:47.037 回答
0

我有一个类似的问题,我有一个类及其子级,当我从父级中删除子级时,它们已从数据库中删除,然后我使用 JPA/EclipseLink在父级( CascadeType.ALL )上使用合并附加新子级,然后孩子们没有在数据库上创建,而是在持久性电机(JPA)中创建。我通过以下方式解决此问题:

1-我在persistence.xml文件中将shared-cache-mode设置为NONE

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 回答
0

我找到的唯一解决方案是创建一个新方法来执行删除并强制 JPA 创建一个新事务。由于这样我丢失了changeSet,我不得不手动找出哪些出版物被删除了。然后我简单地调用那个辅助方法并且出版物被正确删除,但我发现这个解决方案非常难看。

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

        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 回答