blaze-persistence icon indicating copy to clipboard operation
blaze-persistence copied to clipboard

Cascade delete throws an exception about an missing id

Open EugenMayer opened this issue 3 years ago • 1 comments

Description

When deleting a entity of (yet unknown pattern) via cascade, we get this exception java.lang.IllegalArgumentException: Attribute 'id' not found on type 'ModerationPageRevisionState'

Expected behavior

It should work work just like that i suppose.

Actual behavior

Exception with stacktrace

java.lang.IllegalArgumentException: Attribute 'id' not found on type 'ModerationPageRevisionState'

	at com.blazebit.persistence.parser.PathTargetResolvingExpressionVisitor.visit(PathTargetResolvingExpressionVisitor.java:244)
	at com.blazebit.persistence.parser.expression.PropertyExpression.accept(PropertyExpression.java:41)
	at com.blazebit.persistence.parser.PathTargetResolvingExpressionVisitor.visit(PathTargetResolvingExpressionVisitor.java:337)
	at com.blazebit.persistence.parser.expression.PathExpression.accept(PathExpression.java:85)
	at com.blazebit.persistence.impl.JpaUtils.getAttributeForJoining(JpaUtils.java:476)
	at com.blazebit.persistence.impl.JoinManager.implicitJoinSingle(JoinManager.java:3553)
	at com.blazebit.persistence.impl.JoinManager.implicitJoin(JoinManager.java:2932)
	at com.blazebit.persistence.impl.JoinVisitor.visit(JoinVisitor.java:268)
	at com.blazebit.persistence.impl.JoinVisitor.visit(JoinVisitor.java:219)
	at com.blazebit.persistence.parser.expression.PathExpression.accept(PathExpression.java:85)
	at com.blazebit.persistence.impl.JoinVisitor.removeAssociationIdIfPossible(JoinVisitor.java:444)
	at com.blazebit.persistence.impl.JoinVisitor.visit(JoinVisitor.java:376)
	at com.blazebit.persistence.parser.predicate.EqPredicate.accept(EqPredicate.java:57)
	at com.blazebit.persistence.parser.expression.VisitorAdapter.visit(VisitorAdapter.java:223)
	at com.blazebit.persistence.parser.predicate.CompoundPredicate.accept(CompoundPredicate.java:77)
	at com.blazebit.persistence.impl.PredicateManager.acceptVisitor(PredicateManager.java:246)
	at com.blazebit.persistence.impl.AbstractCommonQueryBuilder.applyImplicitJoins(AbstractCommonQueryBuilder.java:2674)
	at com.blazebit.persistence.impl.AbstractCommonQueryBuilder.prepareAndCheck(AbstractCommonQueryBuilder.java:3594)
	at com.blazebit.persistence.impl.AbstractCommonQueryBuilder.getBaseQueryStringWithCheck(AbstractCommonQueryBuilder.java:2813)
	at com.blazebit.persistence.impl.AbstractCommonQueryBuilder.getTypedQuery(AbstractCommonQueryBuilder.java:2828)
	at com.blazebit.persistence.impl.AbstractQueryBuilder.getQuery(AbstractQueryBuilder.java:53)
	at com.blazebit.persistence.impl.AbstractQueryBuilder.getResultList(AbstractQueryBuilder.java:58)
	at com.blazebit.persistence.view.impl.update.flush.UnmappedBasicAttributeCascadeDeleter.removeByOwnerId(UnmappedBasicAttributeCascadeDeleter.java:133)
	at com.blazebit.persistence.view.impl.update.flush.UnmappedBasicAttributeCascadeDeleter.removeByOwnerId(UnmappedBasicAttributeCascadeDeleter.java:192)
	at com.blazebit.persistence.view.impl.update.flush.UnmappedCollectionAttributeCascadeDeleter.removeByOwnerId(UnmappedCollectionAttributeCascadeDeleter.java:125)
	at com.blazebit.persistence.view.impl.update.flush.CompositeAttributeFlusher.remove(CompositeAttributeFlusher.java:996)
	at com.blazebit.persistence.view.impl.update.flush.CompositeAttributeFlusher.remove(CompositeAttributeFlusher.java:938)
	at com.blazebit.persistence.view.impl.update.EntityViewUpdaterImpl.remove(EntityViewUpdaterImpl.java:746)
	at com.blazebit.persistence.view.impl.EntityViewManagerImpl.remove(EntityViewManagerImpl.java:1135)
	at com.blazebit.persistence.view.impl.EntityViewManagerImpl.remove(EntityViewManagerImpl.java:1125)

Steps to reproduce

2 Entities with an OneToOne relation, while the 'childEntity` uses the PK of the parent entity as its own PK (and FK) The parent

@Data
@Entity
@Accessors(chain = true)
@ToString(of = {"id", "title", "lastModified"})
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class PageRevision implements Serializable
{
  @Id
  @Include
  @Column(name = "vid", columnDefinition = "INT(10)")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @OneToOne(mappedBy = "pageRevision", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
  private ModerationPageRevisionState pageModerationState;
}

That is the 'child'

public class ModerationPageRevisionState implements Serializable
{
  @Id
  @Column(name = "vid", columnDefinition = "INT(11)")
  private Long pageRevisionId;

  @OneToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "vid", referencedColumnName = "vid", columnDefinition = "INT(10)", insertable = false,
    updatable = false)
  private PageRevision pageRevision;
}

Environment

Version: 1.6.1 JPA-Provider: Hibernate 5.1.2 DBMS: mariadb:10.3

EugenMayer avatar Feb 21 '22 11:02 EugenMayer

The relevant part is the following:

class Page {
	@OneToMany(mappedBy = "page", cascade = ALL)
	Set<PageRevision> set;
}

class PageRevision {
	@ManyToOne
	Page page;
	
	@OneToOne(mappedBy = "pageRevision", cascade = ALL)
	PageModerationState pageModerationState;
}

class PageModerationState {

	@OneToOne
	PageRevision pageRevision;
}

When running evm.remove(PageIdView.class, 1), the nested CascadeDeleter for pageModerationState lacks the mappedBy information, so the owner id path is just id instead of pageRevision.id

beikov avatar Feb 21 '22 12:02 beikov