Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inheritance cascade of fields with bean inheritance #1846

Open
frensjan opened this issue Oct 17, 2019 · 2 comments
Open

Inheritance cascade of fields with bean inheritance #1846

frensjan opened this issue Oct 17, 2019 · 2 comments
Assignees
Labels

Comments

@frensjan
Copy link

Deletes aren't cascaded to embedded beans referenced using @ElementCollection

Steps to reproduce

The (abstract) data model is:

  • A bean (RootBean) that is inherited by SimpleBean and ComplexBean
  • ComplexBean embeds instances of ElementBean
  • RootBeans are referenced through @OneToMany from ReferencingBean
@Entity
class ReferencingBean {
    @Id
    @GeneratedValue
    public UUID id;

    @OneToMany(cascade = CascadeType.ALL)
    private List<RootBean> rootBeans;

    public ReferencingBean(List<RootBean> rootBeans) { ... }
    public List<RootBean> getRootBeans() { ... }
    public void setRootBeans(List<RootBean> rootBeans) { ... }
}

@Entity
@Inheritance
abstract class RootBean {
    @Id
    @GeneratedValue
    public UUID id;
}

@Entity
class SimpleBean extends RootBean {
    private String value;

    public SimpleBean(String value) { ... }
    public String getValue() { ... }
    public void setValue(String value) { ... }
}

@Entity
class ComplexBean extends RootBean {
    @ElementCollection
    private List<ElementBean> elements;

    public ComplexBean(List<ElementBean> elements) { ... }
    public List<ElementBean> getElements() { ... }
    public void setElements(List<ElementBean> elements) { ... }
}

@Embeddable
class ElementBean {
    @EmbeddedId
    @GeneratedValue
    private Long id;

    @NotNull
    private String value;

    public ElementBean(String value) { ... }
    public String getValue() { ... }
}

Instantiating the data structure described above and then deleting a ReferencingBean fails as illustrated by the test below:

RootBean bean1 = new ComplexBean(asList(new ElementBean("element-1"), new ElementBean("element-2")));
RootBean bean2 = new SimpleBean("simple-1");
ReferencingBean referencingBean = new ReferencingBean(asList(bean1,bean2));

database.save(referencingBean);
database.delete(referencingBean);

assertNull(database.find(RootBean.class, database.getBeanId(bean1)));
assertNull(database.find(RootBean.class, database.getBeanId(bean2)));

with the following output:

2019-10-17 09:37:28,307  INFO [main] io.ebean.config.properties.LoadContext:83 - loaded properties from []
2019-10-17 09:37:28,325  INFO [main] io.ebean.EbeanVersion:31 - ebean version: 11.45.1
2019-10-17 09:37:28,629  INFO [main] io.ebean.datasource.pool.ConnectionPool:297 - DataSourcePool [db] autoCommit[false] transIsolation[READ_COMMITTED] min[2] max[200]
2019-10-17 09:37:28,822  INFO [main] io.ebeaninternal.server.core.DefaultContainer:208 - DatabasePlatform name:db platform:h2
2019-10-17 09:37:29,466  INFO [main] io.ebean.migration.ddl.DdlRunner:65 - Executing db-drop-all.sql - 35 statements
2019-10-17 09:37:29,475  INFO [main] io.ebean.migration.ddl.DdlRunner:65 - Executing db-create-all.sql - 35 statements
2019-10-17 09:37:29,538 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[] insert into referencing_bean (id) values (?); -- bind(3bb12ba3-a997-4466-bb4e-f87ab996d43b)
2019-10-17 09:37:29,547 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[] insert into root_bean (id, referencing_bean_id, dtype) values (?,?,?)
2019-10-17 09:37:29,547 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[]  -- bind(f31c05f1-ab35-45d9-9206-a28ae91eeb7f,3bb12ba3-a997-4466-bb4e-f87ab996d43b,ComplexBean)
2019-10-17 09:37:29,555 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[] insert into root_bean_elements (root_bean_id,id,value) values (?,?,?)
2019-10-17 09:37:29,556 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[]  -- bind(f31c05f1-ab35-45d9-9206-a28ae91eeb7f, null, element-1)
2019-10-17 09:37:29,556 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[]  -- bind(f31c05f1-ab35-45d9-9206-a28ae91eeb7f, null, element-2)
2019-10-17 09:37:29,559 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[] insert into root_bean (id, referencing_bean_id, dtype, value) values (?,?,?,?)
2019-10-17 09:37:29,559 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[]  -- bind(53372fc0-8928-40f1-a1f0-15c66d5d3aaa,3bb12ba3-a997-4466-bb4e-f87ab996d43b,SimpleBean,simple-1)
2019-10-17 09:37:29,591 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[] select t0.id from referencing_bean t0 where t0.id = ?  ; --bind(3bb12ba3-a997-4466-bb4e-f87ab996d43b, )
2019-10-17 09:37:29,595 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[] select t0.dtype, t0.id, t0.value from root_bean t0 where t0.id = ?  ; --bind(f31c05f1-ab35-45d9-9206-a28ae91eeb7f, )
2019-10-17 09:37:29,596 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[] select t0.dtype, t0.id, t0.value from root_bean t0 where t0.id = ?  ; --bind(53372fc0-8928-40f1-a1f0-15c66d5d3aaa, )
2019-10-17 09:37:29,603 DEBUG [main] io.ebeaninternal.server.logger.DSpiLogger:26 - txn[] select t0.id from root_bean t0 where referencing_bean_id=? ; --bind(3bb12ba3-a997-4466-bb4e-f87ab996d43b)



io.ebean.DataIntegrityException: Referential integrity constraint violation: "FK_ROOT_BEAN_ELEMENTS_ROOT_BEAN_ID: PUBLIC.ROOT_BEAN_ELEMENTS FOREIGN KEY(ROOT_BEAN_ID) REFERENCES PUBLIC.ROOT_BEAN(ID) ('f31c05f1-ab35-45d9-9206-a28ae91eeb7f')"; SQL statement:
delete from root_bean where id  in (?,?) [23503-193]

	at io.ebean.config.dbplatform.SqlCodeTranslator.translate(SqlCodeTranslator.java:49)
	at io.ebean.config.dbplatform.DatabasePlatform.translate(DatabasePlatform.java:227)
	at io.ebeaninternal.server.transaction.TransactionManager.translate(TransactionManager.java:243)
	at io.ebeaninternal.server.transaction.JdbcTransaction.translate(JdbcTransaction.java:689)
	at io.ebeaninternal.server.core.PersistRequest.translateSqlException(PersistRequest.java:105)
	at io.ebeaninternal.server.persist.ExeUpdateSql.execute(ExeUpdateSql.java:59)
	at io.ebeaninternal.server.persist.DefaultPersistExecute.executeSqlUpdate(DefaultPersistExecute.java:95)
	at io.ebeaninternal.server.core.PersistRequestUpdateSql.executeNow(PersistRequestUpdateSql.java:85)
	at io.ebeaninternal.server.core.PersistRequest.executeStatement(PersistRequest.java:126)
	at io.ebeaninternal.server.core.PersistRequestUpdateSql.executeOrQueue(PersistRequestUpdateSql.java:95)
	at io.ebeaninternal.server.persist.DefaultPersister.executeOrQueue(DefaultPersister.java:121)
	at io.ebeaninternal.server.persist.DefaultPersister.executeSqlUpdate(DefaultPersister.java:166)
	at io.ebeaninternal.server.persist.DefaultPersister.delete(DefaultPersister.java:827)
	at io.ebeaninternal.server.persist.DefaultPersister.deleteChildrenById(DefaultPersister.java:1123)
	at io.ebeaninternal.server.persist.DefaultPersister.deleteManyDetails(DefaultPersister.java:1099)
	at io.ebeaninternal.server.persist.DefaultPersister.deleteAssocMany(DefaultPersister.java:1065)
	at io.ebeaninternal.server.persist.DefaultPersister.delete(DefaultPersister.java:891)
	at io.ebeaninternal.server.persist.DefaultPersister.deleteRequest(DefaultPersister.java:617)
	at io.ebeaninternal.server.persist.DefaultPersister.deleteRequest(DefaultPersister.java:597)
	at io.ebeaninternal.server.persist.DefaultPersister.delete(DefaultPersister.java:589)
	at io.ebeaninternal.server.core.DefaultServer.delete(DefaultServer.java:1978)
	at io.ebeaninternal.server.core.DefaultServer.delete(DefaultServer.java:1969)
	at ....InheritanceDeleteCascadeTest.test2(InheritanceDeleteCascadeTest.java:49)
	...
Caused by: org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK_ROOT_BEAN_ELEMENTS_ROOT_BEAN_ID: PUBLIC.ROOT_BEAN_ELEMENTS FOREIGN KEY(ROOT_BEAN_ID) REFERENCES PUBLIC.ROOT_BEAN(ID) ('f31c05f1-ab35-45d9-9206-a28ae91eeb7f')"; SQL statement:
delete from root_bean where id  in (?,?) [23503-193]
	at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
	at org.h2.message.DbException.get(DbException.java:179)
	at org.h2.message.DbException.get(DbException.java:155)
	at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:426)
	at org.h2.constraint.ConstraintReferential.checkRowRefTable(ConstraintReferential.java:443)
	at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:318)
	at org.h2.table.Table.fireConstraints(Table.java:967)
	at org.h2.table.Table.fireAfterRow(Table.java:985)
	at org.h2.command.dml.Delete.update(Delete.java:101)
	at org.h2.command.CommandContainer.update(CommandContainer.java:98)
	at org.h2.command.Command.executeUpdate(Command.java:258)
	at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:160)
	at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:146)
	at io.ebean.datasource.pool.ExtendedPreparedStatement.executeUpdate(ExtendedPreparedStatement.java:148)
	at io.ebeaninternal.server.persist.ExeUpdateSql.execute(ExeUpdateSql.java:50)
	... 40 more

By coincidence I discovered a workaround: adding a @PreDelete hook in the RootBean:

@Entity
@Inheritance
public abstract class RootBean {

    ...

    // added as workaround for the issue
    @PreRemove
    public void preRemove() {
    }

}

I hope this workaround gives a clue for a solution.

Let me know if I can do anything to help.

@frensjan frensjan changed the title Inheritance cascade of Embeddable Inheritance cascade of fields with bean inheritance Oct 17, 2019
@frensjan
Copy link
Author

I just discovered that the issue isn't tied to the use of @ElementCollection and @Embeddable in particular. With the setup as described above, but with the ComplexBean.element relationship expressed through @OneToMany (and ElementBean being an @Entity, not @Embeddable).

Sorry for the confusion.

rbygrave added a commit that referenced this issue Oct 18, 2019
Note this includes the workaround RootBean.preRemove(), so doesn't fail
@rbygrave
Copy link
Member

Note that the workaround works due to BeanDescriptor.isDeleteByBulk() ... doesn't allow bulk delete due to the persistController that is added by RootBean.preDelete().

@rbygrave rbygrave self-assigned this Oct 18, 2019
@rbygrave rbygrave added the bug label Oct 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants