Skip to content

Commit a7668c3

Browse files
committed
HSEARCH-5517 Adjust index plan updates caused by "association" for deleted entities
1 parent ad6ddba commit a7668c3

File tree

2 files changed

+148
-1
lines changed

2 files changed

+148
-1
lines changed

integrationtest/mapper/orm/src/test/java/org/hibernate/search/integrationtest/mapper/orm/automaticindexing/association/bytype/onetoone/ownedbycontaining/AutomaticIndexingOneToOneOwnedByContainingEagerOnBothSidesIT.java

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
*/
55
package org.hibernate.search.integrationtest.mapper.orm.automaticindexing.association.bytype.onetoone.ownedbycontaining;
66

7+
import static org.hibernate.search.util.impl.integrationtest.mapper.orm.OrmUtils.with;
8+
79
import java.util.ArrayList;
810
import java.util.List;
911
import java.util.Optional;
1012
import java.util.stream.Stream;
1113

1214
import jakarta.persistence.Basic;
15+
import jakarta.persistence.CascadeType;
1316
import jakarta.persistence.CollectionTable;
1417
import jakarta.persistence.Column;
1518
import jakarta.persistence.ElementCollection;
@@ -18,6 +21,7 @@
1821
import jakarta.persistence.Id;
1922
import jakarta.persistence.JoinColumn;
2023
import jakarta.persistence.ManyToOne;
24+
import jakarta.persistence.MapsId;
2125
import jakarta.persistence.OneToOne;
2226
import jakarta.persistence.OrderColumn;
2327
import jakarta.persistence.Transient;
@@ -29,6 +33,7 @@
2933
import org.hibernate.search.integrationtest.mapper.orm.automaticindexing.association.bytype.accessor.PropertyAccessor;
3034
import org.hibernate.search.mapper.pojo.automaticindexing.ReindexOnUpdate;
3135
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.AssociationInverseSide;
36+
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.DocumentId;
3237
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField;
3338
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
3439
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexedEmbedded;
@@ -37,6 +42,8 @@
3742
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyValue;
3843
import org.hibernate.search.util.impl.integrationtest.mapper.orm.OrmSetupHelper;
3944

45+
import org.junit.jupiter.api.Test;
46+
4047
/**
4148
* Test automatic indexing caused by single-valued association updates
4249
* or by updates of associated (contained) entities,
@@ -78,9 +85,47 @@ protected OrmSetupHelper.SetupContext additionalSetup(OrmSetupHelper.SetupContex
7885
// See https://hibernate.zulipchat.com/#narrow/stream/132094-hibernate-orm-dev/topic/lazy.20associations.20with.20ORM.206
7986
setupContext.withProperty( AvailableSettings.MAX_FETCH_DEPTH, 1 );
8087

88+
setupContext.withAnnotatedTypes( CascadingParent.class, CascadableChildMapsId.class );
89+
setupContext.dataClearing( config -> config.manualDatabaseCleanup( session -> {
90+
session.getSessionFactory().getSchemaManager().truncateMappedObjects();
91+
} ) );
92+
backendMock.expectAnySchema( CascadableChildMapsId.INDEX );
93+
8194
return setupContext;
8295
}
8396

97+
@Test
98+
void deleteWithCascade() {
99+
with( sessionFactory ).runInTransaction( session -> {
100+
CascadingParent p = new CascadingParent( 1L, "Parent" );
101+
CascadableChildMapsId entity = new CascadableChildMapsId( p, "Entity" );
102+
103+
session.persist( p );
104+
session.persist( entity );
105+
106+
backendMock.expectWorks( CascadableChildMapsId.INDEX )
107+
.add( "1", b -> b
108+
.field( "name", "Entity" )
109+
.objectField( "parent", b2 -> b2
110+
.field( "parentName", "Parent" ) )
111+
);
112+
} );
113+
backendMock.verifyExpectationsMet();
114+
115+
with( sessionFactory ).runInTransaction( session -> {
116+
CascadingParent parent = session.find( CascadingParent.class, 1L );
117+
118+
CascadableChildMapsId child = session.find( CascadableChildMapsId.class, 1L );
119+
child.setName( "to-be-deleted" );
120+
session.persist( child );
121+
session.remove( parent );
122+
123+
backendMock.expectWorks( CascadableChildMapsId.INDEX )
124+
.delete( "1" );
125+
} );
126+
backendMock.verifyExpectationsMet();
127+
}
128+
84129
@Entity(name = "containing")
85130
public static class ContainingEntity {
86131

@@ -848,4 +893,101 @@ public PropertyAccessor<ContainedEmbeddable, ContainingEntity> containingAsNonIn
848893
};
849894
}
850895

896+
@Entity
897+
public static class CascadingParent {
898+
899+
@Id
900+
private Long id;
901+
902+
@GenericField
903+
private String parentName;
904+
905+
@OneToOne(mappedBy = "parent", cascade = CascadeType.ALL)
906+
private CascadableChildMapsId cascadableChildMapsId;
907+
908+
public CascadingParent() {
909+
}
910+
911+
public CascadingParent(Long id, String parentName) {
912+
this.id = id;
913+
this.parentName = parentName;
914+
}
915+
916+
public Long getId() {
917+
return id;
918+
}
919+
920+
public void setId(Long id) {
921+
this.id = id;
922+
}
923+
924+
public String getParentName() {
925+
return parentName;
926+
}
927+
928+
public void setParentName(String parentName) {
929+
this.parentName = parentName;
930+
}
931+
932+
public CascadableChildMapsId getMapsIdJoinColumnChild() {
933+
return cascadableChildMapsId;
934+
}
935+
936+
public void setMapsIdJoinColumnChild(CascadableChildMapsId cascadableChildMapsId) {
937+
this.cascadableChildMapsId = cascadableChildMapsId;
938+
}
939+
940+
}
941+
942+
@Entity
943+
@Indexed(index = CascadableChildMapsId.INDEX)
944+
public static class CascadableChildMapsId {
945+
static final String INDEX = "CascadableChildMapsId";
946+
947+
@Id
948+
@DocumentId
949+
private Long id;
950+
951+
@MapsId
952+
@JoinColumn(name = "PARENT_ID_CUSTOM_NAME")
953+
@OneToOne
954+
@IndexedEmbedded
955+
@AssociationInverseSide(inversePath = @ObjectPath(@PropertyValue(propertyName = "cascadableChildMapsId")))
956+
private CascadingParent parent;
957+
958+
@GenericField
959+
@Column(name = "NAME")
960+
private String name;
961+
962+
protected CascadableChildMapsId() {
963+
}
964+
965+
public CascadableChildMapsId(Long id, String name) {
966+
this.id = id;
967+
this.name = name;
968+
}
969+
970+
public CascadableChildMapsId(CascadingParent parent, String name) {
971+
this.id = parent.getId();
972+
this.parent = parent;
973+
this.name = name;
974+
}
975+
976+
public Long getId() {
977+
return id;
978+
}
979+
980+
public CascadingParent getParent() {
981+
return parent;
982+
}
983+
984+
public String getName() {
985+
return name;
986+
}
987+
988+
public void setName(String name) {
989+
this.name = name;
990+
}
991+
}
992+
851993
}

mapper/pojo-base/src/main/java/org/hibernate/search/mapper/pojo/work/impl/AbstractPojoTypeIndexingPlan.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,12 @@ void updateBecauseOfContainedAssociation(Object entity, int dirtyAssociationPath
120120
BitSet dirtyPaths =
121121
typeContext().reindexingResolver().dirtySelfOrContainingFilter().filter( dirtyAssociationPathOrdinal );
122122
if ( dirtyPaths != null ) {
123-
getState( identifier ).addOrUpdate( entitySupplier, dirtyPaths, false, false );
123+
S state = getState( identifier );
124+
// If the current entity state is "removed" and we are trying to add/update something because of
125+
// the association, then we should ignore that action, since the actual value is ... removed?!
126+
if ( !EntityStatus.ABSENT.equals( state.currentStatus ) ) {
127+
state.addOrUpdate( entitySupplier, dirtyPaths, false, false );
128+
}
124129
}
125130
}
126131

0 commit comments

Comments
 (0)