在我目前的项目中,我有一个可以发布到其他系统的实体。为了跟踪出版物,实体具有称为“出版物”的关系。我正在使用Eclipselink。
此实体bean还具有“PreUpdate”注释方法。
为了能够使其他系统数据保持最新,我创建了一个围绕调用PreUpdate方法执行的Aspect。根据更改的属性,我需要删除一些出版物。一切都工作得很好。
我遇到的问题是portal-publishing组件正确发送删除命令并从实体“publications”列表中删除发布。我甚至可以在变更集中看到JPA已经注意到“发布”属性已经改变了。刷新事务后,缓存的实体不再具有已删除的发布。不幸的是,数据库仍然存在,当系统重新启动或者再次从DB加载实体时,再次出现了发布元数据。
我尝试了所有的一切。我甚至设法从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);
}
}
}
}
}
}
}
克里斯
答案 0 :(得分:2)
问题是PreUpdate是在提交过程中引发的,当时已经计算了一组更改,并且已经计算了要删除的对象集。
理想情况下,您可以在应用程序逻辑中执行类似的操作,而不是通过持久性事件。
您可以尝试直接从您的事件执行DeleteObjectQuery(而不是使用em.remove()),这可能会有效,但通常最好在您的应用程序中执行此逻辑。
jpaEntityManager.getUnitOfWork()DeleteObject的(对象);
另请注意,getCurrentChanges()计算更改,在PreUpdate事件中已经计算了更改,因此您应该能够使用getUnitOfWorkChangeSet()。
答案 1 :(得分:0)
我找到的唯一解决方案是创建一个新的方法来执行删除并强制JPA创建一个新的Transaction。因此我失去了changeSet,我不得不手动找出哪些出版物被删除了。然后我只是调用那个帮助器方法并正确删除了这些出版物,但我发现这个解决方案非常难看。
@Transactional @Around(“execution(* de.cware.services.truck.model.Truck.jpaPreUpdate(..))”) public Object truckPreUpdate(final ProceedingJoinPoint pjp)抛出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();
}
}
}
为什么我的第一个版本不起作用?
答案 2 :(得分:0)
我有一个类似的问题,我有一个类及其子项,当我从父项中删除子项时,它们从DB中删除,然后我在类Parent上使用merge附加新子项( CascadeType.ALL )使用JPA / EclipseLink,然后孩子们没有在DB上创建,而是在持久性Motor(JPA)中创建。我解决了这个问题:
1-我在 persistence.xml 文件中将 shared-cache-mode 设置为 NONE
2-当我移除孩子时,我立即执行了这个:
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
getEntityManager().getEntityManagerFactory().getCache().evictAll();
}
这就是全部。我希望这会有所帮助。