如何在 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
和其他实体,如TableOne
、TableTwo
和TableThree
。所有扩展 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
实体的结果。对其他实体实施完全相同。这样就可以解决你的问题了。
我有三个具有相同列名和类型的 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
和其他实体,如TableOne
、TableTwo
和TableThree
。所有扩展 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
实体的结果。对其他实体实施完全相同。这样就可以解决你的问题了。