Skip to content

Commit 4ebe234

Browse files
committed
HSEARCH-5517 Adjust index plan updates caused by "association" for deleted entities
1 parent 02ad020 commit 4ebe234

File tree

2 files changed

+147
-1
lines changed

2 files changed

+147
-1
lines changed

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

Lines changed: 141 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,46 @@ 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.remove( parent );
121+
122+
backendMock.expectWorks( CascadableChildMapsId.INDEX )
123+
.delete( "1" );
124+
} );
125+
backendMock.verifyExpectationsMet();
126+
}
127+
84128
@Entity(name = "containing")
85129
public static class ContainingEntity {
86130

@@ -848,4 +892,101 @@ public PropertyAccessor<ContainedEmbeddable, ContainingEntity> containingAsNonIn
848892
};
849893
}
850894

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

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)