Skip to content
Advertisement

How use generic entity name in JPQL

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.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement