【问题标题】:How use generic entity name in JPQL如何在 JPQL 中使用通用实体名称
【发布时间】:2021-09-27 22:57:24
【问题描述】:

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

示例: |表 1 |表 2 |表 3 | | ------ | ------ | -------- | |身份证 |身份证 |身份证 | |姓名 |姓名 |姓名 | |福 |福 |福 | |酒吧 |酒吧 |酒吧 |


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

实体父级:

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

【问题讨论】:

  • 我会继续猜测这是不可能的。最后 JPQL 变成了一个 SQL 查询。 SQL查询需要知道它需要查询什么表。 JPQL 从查询中的实体获取该信息。僵局。我建议使用本地查询 - 这样您就可以将表名作为参数传递。

标签: java jpa spring-data-jpa jpql


【解决方案1】:

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
}

并从实体服务类调用此存储库:

@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 实体的结果。对其他实体执行完全相同的操作。因此,您可以解决您的问题。

【讨论】:

    猜你喜欢
    • 2011-03-06
    • 2018-11-13
    • 2020-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多