Search code examples
javaspring-data-jpaspring-data

Using @MappedSuperclass in spring repository @Query


I am trying to define a common query for all repositories extending my base repository:

@NoRepositoryBean
public interface DocumentRepository<T extends BaseDocument> extends JpaRepository<T, Long> {

    @Query(value = "FROM BaseDocument bd WHERE (bd.createdAt IS NULL OR :to IS NULL OR bd.createdAt < :to) AND (bd.deletedAt IS NULL OR :from IS NULL OR bd.deletedAt > :from)")
    Iterable<T> findAllActiveBetween(OffsetDateTime from, OffsetDateTime to);
}

@MappedSuperclass
@Where(clause="deleted_at IS NULL")
abstract public class BaseDocument {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private OffsetDateTime createdAt;

    private OffsetDateTime deletedAt;
}

The problematic part is using BaseDocument in @Query. Is it possible to define such a method without duplication in all sub-repositories?


Solution

  • When you use @MappedSuperclass the inherited classes do not share a table to select from, so each of them needs a separate query. Inheritance of the repository cannot help you here.

    If you use another inheritance strategy, for example a joined multiple table inheritance it would be possible to select from the table of the superclass and then you can use the java objects to navigate. If you need to use properties from the subclass in the query, each subclass would need to implement their own queries of course.

    @NoRepositoryBean
    public interface DocumentRepository<T extends BaseDocument> extends JpaRepository<T, Long> {
    
        @Query(value = "FROM BaseDocument bd WHERE (bd.createdAt IS NULL OR :to IS NULL OR bd.createdAt < :to) AND (bd.deletedAt IS NULL OR :from IS NULL OR bd.deletedAt > :from)")
        Iterable<T> findAllActiveBetween(OffsetDateTime from, OffsetDateTime to);
    }
    
    @Entity
    @Inheritance(strategy=InheritanceType.JOINED)
    @DiscriminatorColumn(name="BaseDocument_TYPE")
    @Table(name="BaseDocument")
    abstract public class BaseDocument {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        private OffsetDateTime createdAt;
    
        private OffsetDateTime deletedAt;
    }
    
    @Entity
    @DiscriminatorValue("TextDocument")
    @Table(name="TextDocument")
    public class TextDocument extends BaseDocument {
      private String text;
    }
    
    @Entity
    @DiscriminatorValue("AudioDocument")
    @Table(name="AudioDocument")
    public class AudioDocument extends BaseDocument {
      private byte [] audio;
    }