glenlivet1986
glenlivet1986

Reputation: 260

How to disable delete cascading for JPA joined inheriting Entity?

I have three entities. Both ResolvedCorpus and UnqualifiedCorpus are subclasses of Corpus to help model and address certain concerns for some Corpus.

Joined inheritance type is selected for data persistence via JPA. The entities are defined as below.

@Entity
@Table(name="corpus")
@Inheritance(strategy = InheritanceType.JOINED)
public class Corpus implements Serializable  {}

@Entity
@Table(name = "resolved_corpus")
@OnDelete(action=OnDeleteAction.CASCADE)
public class ResolvedCorpus extends Corpus {}

@Entity
@Table(name="unqualified_corpus")
@OnDelete(action=OnDeleteAction.NO_ACTION)
public class UnqualifiedCorpus extends Corpus {}

With @OnDelete annotation specified, I want to achieve the follows:

  1. when a ResolvedCorpus gets deleted via repository.delete(), the corresponding Corpus is deleted as well in Table corpus;
  2. when a UnqualifiedCorpus gets deleted via repository.delete(), the corresponding Corpus is remained.

However, @OnDelete does not work as expected. BTW, H2 is used as the embedded DB.

The testing code is copied below.

        //create corpora, one for each type: normal, resolved, unqualified.
        Corpus normal = new Corpus();
        normal.setName("normal");
        corpusRepository.save(normal);

        ResolvedCorpus resolved = new ResolvedCorpus();
        resolved.setName("resolved");
        resolved.setResolved("resolved");
        resolvedCorpusRepository.save(resolved);

        UnqualifiedCorpus unqualified = new UnqualifiedCorpus();
        unqualified.setName("unqualified");
        unqualified.setReason("unqualified");
        unqualifiedCorpusRepository.save(unqualified);

        //query
        // 3 records are expected in corpus table
        // 1 record in resolved table
        // 1 in unqualified table
        assertTrue(corpusRepository.count() == 3);
        assertTrue(resolvedCorpusRepository.count() == 1);
        assertTrue(unqualifiedCorpusRepository.count() == 1);
        resolvedCorpusRepository.findAll().forEach((item) -> {
            assertTrue(item.getName().equals("resolved"));
        });
        unqualifiedCorpusRepository.findAll().forEach((item) -> {
            assertTrue(item.getName().equals("unqualified"));
        });

        //delete
        // when deleting resolved, the delete action is expected to get cascaded to ancestor table "corpus", as OnDeleteAction suggested.
        // when deleting unqualified, the delete action is not expected to get cascaded to ancestor table "corpus", as OnDeleteAction suggested.
        resolvedCorpusRepository.deleteAll();
        unqualifiedCorpusRepository.deleteAll();
        //query
        //HOWEVER, OnDeleteAction.NO_ACTION is NOT working as expected, and this assertion is failed.
        assertTrue(corpusRepository.count() == 2);

And you can find the testing application here.

I diagnosed the DDL for table creation and row deletion. I suspect the @OnDelete is aiming to do the opposite, which means it controls how sub-entity shall behave when the base entity object gets deleted. when calling repository.delete(Resolved), the DDL generated is delete from corpus instead of delete from resolved_corpus; and for Unqualified, both delete from unqualified and delete from corpus are called in order.

I guess, the request like I have should be a reasonable feature expected from JPA, but I cannot find a proper solution after some search online.

Upvotes: 1

Views: 792

Answers (0)

Related Questions