I have three tables with same column name and types, what changes is just the table name.
Example: | TABLE1 | TABLE2 | TABLE3 | | —— | —— | ——- | | ID | ID | ID | | NAME | NAME | NAME | | FOO | FOO | FOO | | BAR | BAR | BAR |
I have three entities, one to each table.
Entity Parent:
public class EntityParent { @Id @Column(name = "ID") private Long id; @Column(name = "NAME") private String name; @Column(name = "FOO") private String foo; @Column(name = "BAR") private String bar; }
Entity Childs:
@Table(name = "TABLE1") public class Entity1 extends EntityParent { }
@Table(name = "TABLE2") public class Entity2 extends EntityParent { }
@Table(name = "TABLE3") public class Entity3 extends EntityParent { }
I have a generic repository, with some methods:
@NoRepositoryBean public interface EntityGenericRepository<T extends EntityParent, ID> extends JpaRepository<T, ID> { List<T> findAllByName(String name); List<T> findAllByFooAndBar(String foo, String bar); List<T> findAllByNameOrFoo(String name, String foo); }
So far so good.
See code repetition below, with methods findEntityXToDto
:
@Repository public interface Entity1Repository extends EntityGenericRepository<Entity1, Long> { @Query("SELECT new com.package.MyDTO(e.foo, e.bar) FROM Entity1 e WHERE e.name = :name") List<MyDTO> findEntity1ToDto(@Param("name") String name); }
@Repository public interface Entity2Repository extends EntityGenericRepository<Entity2, Long> { @Query("SELECT new com.package.MyDTO(e.foo, e.bar) FROM Entity2 e WHERE e.name = :name") List<MyDTO> findEntity2ToDto(@Param("name") String name); }
@Repository public interface Entity3Repository extends EntityGenericRepository<Entity3, Long> { @Query("SELECT new com.package.MyDTO(e.foo, e.bar) FROM Entity3 e WHERE e.name = :name") List<MyDTO> findEntity3ToDto(@Param("name") String name); }
It’s here problem. How create SELECT JPQL generic? Something as:
SELECT new com.package.MyDTO(t.foo, t.bar) FROM T t WHERE t.name = :name
Advertisement
Answer
Spring Data JPA release 1.4 supports the usage of restricted SpEL
template expressions in manually defined queries that are defined with @Query
. It supports a variable called entitiyName
. It inserts the entityName
of the domain type associated with the given repository. I would suggest using separate repositories and pass the SpEL
there. For example:
Let you have a BaseEntity
and other entities like TableOne
, TableTwo
and TableThree
. All extends the BaseEntity
and have the exact same attributes.
@MappedSuperclass @Data public class BaseEntity { @Id private String id; private String columnVal; }
Create a base repository with @NoRepositoryBean
annotation as it prevents spring to implement the repository on this base repository.
@NoRepositoryBean public interface DemoRepository<T extends BaseEntity> extends JpaRepository<T, String> { @Query("select u from #{#entityName} u where u.columnVal = ?1") List<T> findByColumnVal(String columnVal); }
Finally Implement your own repository based on each entity:
@Repository public interface TableOneRepository extends DemoRepository<TableOne> { //add more methods if needed }
And call this repository from the entity wise service class:
@Service public class TableOneService { private final TableOneRepository repository; @Autowired public TableOneService(TableOneRepository repository) { this.repository = repository; } public List<TableOne> demoMethod(String val) { return this.repository.findByColumnVal(val); } }
Now just call the method demoMethod
and you’ll get result for TableOne
entity. Implement exactly the same for the other entities. Hence you can solve your problem.