如何在 JPQL 中使用通用实体名称

How use generic entity name in JPQL

我有三个具有相同列名和类型的 table,变化只是 table 名称。

示例: |表 1 |表 2 |表 3 | | ------ | ------ | ------ | |编号 |编号 |编号 | |姓名 |姓名 |姓名 | |富 |富 |富 | |酒吧 |酒吧 |酒吧 |


我有三个实体,每个实体一个 table。

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

实体孩子:

@Table(name = "TABLE1")
public class Entity1 extends EntityParent {
}
@Table(name = "TABLE2")
public class Entity2 extends EntityParent {
}
@Table(name = "TABLE3")
public class Entity3 extends EntityParent {
}

我有一个通用存储库,其中包含一些方法:

@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);

}

到目前为止一切顺利。 请参阅下面的代码重复,使用方法 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);

}

问题来了。如何创建 SELECT JPQL 泛型? 东西如:

SELECT new com.package.MyDTO(t.foo, t.bar) FROM T t WHERE t.name = :name

Spring Data JPA 1.4 版支持在使用 @Query 定义的手动定义查询中使用受限 SpEL 模板表达式。它支持一个名为 entitiyName 的变量。它插入与给定存储库关联的域类型的 entityName。我建议使用单独的存储库并在那里传递 SpEL 。例如:

让你拥有BaseEntity和其他实体,如TableOneTableTwoTableThree。所有扩展 BaseEntity 并具有完全相同的属性。

@MappedSuperclass
@Data
public class BaseEntity {
    @Id
    private String id;
    private String columnVal;
}

创建带有 @NoRepositoryBean 注释的基本存储库,因为它会阻止 spring 在此基本存储库上实现存储库。

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

最后基于每个实体实现自己的存储库:

@Repository
public interface TableOneRepository extends DemoRepository<TableOne> {
    //add more methods if needed
}

并从实体智能服务调用此存储库 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);
    }

}

现在只需调用方法 demoMethod,您将获得 TableOne 实体的结果。对其他实体实施完全相同。这样就可以解决你的问题了。