Using @MappedSuperclass in spring repository @Query
Asked Answered
D

2

2

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?

Droopy answered 7/12, 2021 at 12:34 Comment(0)
D
1

This is possible with spel-expressions, specifically #{#entityName} which is usable on spring-data-repositories and expands to the domain type of your repository.

All you need to do is replace your BaseDocument with #{#entityName}.

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

    @Query(value = "FROM #{#entityName} 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);
}
Diaphaneity answered 27/3 at 15:51 Comment(0)
F
2

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;
}

Facer answered 7/12, 2021 at 12:55 Comment(0)
D
1

This is possible with spel-expressions, specifically #{#entityName} which is usable on spring-data-repositories and expands to the domain type of your repository.

All you need to do is replace your BaseDocument with #{#entityName}.

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

    @Query(value = "FROM #{#entityName} 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);
}
Diaphaneity answered 27/3 at 15:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.