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.