diff --git a/CHANGELOG.md b/CHANGELOG.md index c4873b2b10..d470ffd6ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ None yet * Fix issues with de-serializing of singular entity view attributes that use a collection type * Add Cockroach DBMS detection and a `DbmsDialect` implementation * Fix various issues with type resolving paths that match entity names +* Fix issues with remove view by id when element type of cascaded collection uses embedded id ### Backwards-incompatible changes diff --git a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/EntityViewUpdaterImpl.java b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/EntityViewUpdaterImpl.java index bc413e6628..d0bd9eafa8 100644 --- a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/EntityViewUpdaterImpl.java +++ b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/EntityViewUpdaterImpl.java @@ -1372,19 +1372,17 @@ private static CollectionRemoveListener createOrphanRemoveListener(AbstractMetho if (!attribute.isOrphanRemoval()) { return null; } - - if (elementDescriptor.isSubview()) { - return new ViewCollectionRemoveListener(elementDescriptor.getLoadOnlyViewToEntityMapper()); - } else { - return EntityCollectionRemoveListener.INSTANCE; - } + return createCollectionRemoveListener(elementDescriptor); } private static CollectionRemoveListener createCascadeDeleteListener(AbstractMethodAttribute attribute, TypeDescriptor elementDescriptor) { if (!attribute.isDeleteCascaded()) { return null; } + return createCollectionRemoveListener(elementDescriptor); + } + private static CollectionRemoveListener createCollectionRemoveListener(TypeDescriptor elementDescriptor) { if (elementDescriptor.isSubview()) { return new ViewCollectionRemoveListener(elementDescriptor.getLoadOnlyViewToEntityMapper()); } else { diff --git a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/flush/InverseFlusher.java b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/flush/InverseFlusher.java index 4821522bd2..5d0d9c605a 100644 --- a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/flush/InverseFlusher.java +++ b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/flush/InverseFlusher.java @@ -22,6 +22,7 @@ import com.blazebit.persistence.parser.util.JpaMetamodelUtils; import com.blazebit.persistence.spi.ExtendedAttribute; import com.blazebit.persistence.spi.ExtendedManagedType; +import com.blazebit.persistence.view.EntityViewSetting; import com.blazebit.persistence.view.OptimisticLockException; import com.blazebit.persistence.view.impl.EntityViewManagerImpl; import com.blazebit.persistence.view.impl.accessor.Accessors; @@ -46,6 +47,7 @@ import com.blazebit.persistence.view.impl.update.EntityViewUpdaterImpl; import com.blazebit.persistence.view.impl.update.UpdateContext; import com.blazebit.persistence.view.metamodel.ManagedViewType; +import com.blazebit.persistence.view.metamodel.MethodAttribute; import com.blazebit.persistence.view.metamodel.PluralAttribute; import com.blazebit.persistence.view.metamodel.SingularAttribute; import com.blazebit.persistence.view.metamodel.Type; @@ -73,6 +75,7 @@ public final class InverseFlusher { private final String attributeName; private final String parentIdAttributeName; private final String childIdAttributeName; + private final Class childIdViewClass; private final UnmappedAttributeCascadeDeleter deleter; // Maps the parent view object to an entity via means of em.getReference private final ViewToEntityMapper parentReferenceViewToEntityMapper; @@ -93,7 +96,7 @@ public final class InverseFlusher { private final Mapper parentEntityOnChildEntityMapper; private final InverseEntityToEntityMapper childEntityToEntityMapper; - public InverseFlusher(Class parentEntityClass, String attributeName, String parentIdAttributeName, String childIdAttributeName, UnmappedAttributeCascadeDeleter deleter, + public InverseFlusher(Class parentEntityClass, String attributeName, String parentIdAttributeName, String childIdAttributeName, Class childIdViewClass, UnmappedAttributeCascadeDeleter deleter, ViewToEntityMapper parentReferenceViewToEntityMapper, DirtyAttributeFlusher parentReferenceAttributeFlusher, Mapper parentEntityOnChildViewMapper, TargetViewClassBasedInverseViewToEntityMapper childViewToEntityMapper, ViewToEntityMapper childReferenceViewToEntityMapper, Mapper parentEntityOnChildEntityMapper, InverseEntityToEntityMapper childEntityToEntityMapper) { @@ -101,6 +104,7 @@ public InverseFlusher(Class parentEntityClass, String attributeName, String p this.attributeName = attributeName; this.parentIdAttributeName = parentIdAttributeName; this.childIdAttributeName = childIdAttributeName; + this.childIdViewClass = childIdViewClass; this.deleter = deleter; this.parentReferenceViewToEntityMapper = parentReferenceViewToEntityMapper; this.parentReferenceAttributeFlusher = parentReferenceAttributeFlusher; @@ -283,6 +287,7 @@ public static InverseFlusher forAttribute(EntityViewManagerImpl evm, Map< UnmappedAttributeCascadeDeleter deleter = null; String parentIdAttributeName = null; String childIdAttributeName = null; + Class childIdViewClass = null; // Only construct when orphanRemoval or delete cascading is enabled, orphanRemoval implies delete cascading if (attribute.isDeleteCascaded()) { EntityMetamodel entityMetamodel = evm.getMetamodel().getEntityMetamodel(); @@ -298,6 +303,13 @@ public static InverseFlusher forAttribute(EntityViewManagerImpl evm, Map< } else { ExtendedAttribute extendedAttribute = elementManagedType.getAttribute(mapping); if (childTypeDescriptor.isSubview()) { + if (elementType instanceof ViewType) { + MethodAttribute idAttribute = ((ViewType) elementType).getIdAttribute(); + if (idAttribute.isSubview()) { + // in this case, we need to fetch the id as view as the deleter expects it this way + childIdViewClass = idAttribute.getJavaType(); + } + } deleter = new ViewTypeCascadeDeleter(childTypeDescriptor.getViewToEntityMapper()); } else if (childTypeDescriptor.isJpaEntity()) { deleter = new UnmappedBasicAttributeCascadeDeleter(evm, mapping, extendedAttribute, mapping + "." + parentIdAttributeName, false); @@ -343,6 +355,7 @@ public static InverseFlusher forAttribute(EntityViewManagerImpl evm, Map< attribute.getMapping(), parentIdAttributeName, childIdAttributeName, + childIdViewClass, deleter, parentReferenceViewToEntityMapper, parentReferenceAttributeFlusher, @@ -383,11 +396,15 @@ public void removeByOwnerIdOnly(UpdateContext context, Object ownerId) { public List removeByOwnerId(UpdateContext context, Object ownerId) { EntityViewManagerImpl evm = context.getEntityViewManager(); - List elementIds = (List) evm.getCriteriaBuilderFactory().create(context.getEntityManager(), parentEntityClass, "e") - .where(parentIdAttributeName).eq(ownerId) - .where("e." + attributeName + "." + childIdAttributeName).isNotNull() - .select("e." + attributeName + "." + childIdAttributeName) - .getResultList(); + CriteriaBuilder cb = (CriteriaBuilder) evm.getCriteriaBuilderFactory().create(context.getEntityManager(), parentEntityClass, "e") + .where(parentIdAttributeName).eq(ownerId) + .where("e." + attributeName + "." + childIdAttributeName).isNotNull(); + if (childIdViewClass == null) { + cb.select("e." + attributeName + "." + childIdAttributeName); + } else { + evm.applySetting(EntityViewSetting.create(childIdViewClass), cb, "e." + attributeName + "." + childIdAttributeName); + } + List elementIds = cb.getResultList(); if (!elementIds.isEmpty()) { // We must always delete this, otherwise we might get a constraint violation because of the cascading delete removeByOwnerIdOnly(context, ownerId); diff --git a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/flush/ViewCollectionRemoveListener.java b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/flush/ViewCollectionRemoveListener.java index e6d3f39874..8306692b47 100644 --- a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/flush/ViewCollectionRemoveListener.java +++ b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/update/flush/ViewCollectionRemoveListener.java @@ -35,7 +35,8 @@ public ViewCollectionRemoveListener(ViewToEntityMapper viewToEntityMapper) { @Override public void onEntityCollectionRemove(UpdateContext context, Object element) { - viewToEntityMapper.removeById(context, viewToEntityMapper.getEntityIdAccessor().getValue(element)); + Object viewId = ((CompositeAttributeFlusher) viewToEntityMapper.getFullGraphNode()).createViewIdByEntityId(viewToEntityMapper.getEntityIdAccessor().getValue(element)); + viewToEntityMapper.removeById(context, viewId); } @Override diff --git a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/embedded/complex/EntityViewUpdateSubviewInverseEmbeddedComplexTest.java b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/embedded/complex/EntityViewUpdateSubviewInverseEmbeddedComplexTest.java index c5bc9883fb..4d37fe4823 100644 --- a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/embedded/complex/EntityViewUpdateSubviewInverseEmbeddedComplexTest.java +++ b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/update/subview/inverse/embedded/complex/EntityViewUpdateSubviewInverseEmbeddedComplexTest.java @@ -213,6 +213,29 @@ public void testRemoveReadOnlyElementFromCollection() { Assert.assertEquals(0, legacyOrder.getPositions().size()); } + // Test for https://github.com/Blazebit/blaze-persistence/issues/1299 + @Test + public void testRemoveById() { + // Given + UpdatableLegacyOrderView newOrder = evm.create(UpdatableLegacyOrderView.class); + UpdatableLegacyOrderPositionView position = evm.create(UpdatableLegacyOrderPositionView.class); + position.getId().setPositionId(0); + position.setArticleNumber("123"); + newOrder.getPositions().add(position); + update(newOrder); + + // When + em.clear(); + evm.remove(em, UpdatableLegacyOrderView.class, newOrder.getId()); + em.flush(); + em.clear(); + + // Then + LegacyOrder legacyOrder = em.find(LegacyOrder.class, newOrder.getId()); + Assert.assertNull(legacyOrder); + + } + @Test public void testAddElementCreateViewToCollection() { // Given