【问题标题】:Programmatically changing SQL query and mapping, generating by JPA/Hibernate以编程方式更改 SQL 查询和映射,由 JPA/Hibernate 生成
【发布时间】:2021-11-01 17:17:44
【问题描述】:

我的目标是拦截由 JPA 生成的“原始”SQL 查询,其下带有 Hibernate(这个原始请求非常复杂,通过 JPA 标准 API 生成,有时需要快速更改,所以我不能只是移动到本机 SQL),对其进行一些更改(Hibernate 无法做的更改,即删除连接实体表中不必要的列),然后执行它并映射到原始查询所针对的相同实体结构。 到目前为止我的进展:

  1. 从 JPA TypedQuery 获得 Hibernate 查询
org.hibernate.Query hquery = typedQuery.unwrap(org.hibernate.Query.class);
  1. 从 hql 请求中获得原生 SQL(可以从实体管理器的 hquery 对象中提取所提供方法的所有必要参数):
private String hqlToSql (SessionFactory sessionFactory, String hqlQueryText, EntityGraphQueryHint egqh) {
    QueryTranslatorFactory qtf = new ASTQueryTranslatorFactory();
    SessionFactoryImplementer sfi = (SessionFactoryImplementer) sessionFactory;
    QueryTranslator translator = qtf.createQueryTranslator(hqlQueryText, hqlQueryText, Collections.EMPTY_MAP, sfi, egqh);
    translator.compile(Collections.EMPTY_MAP, false);
    return translator.getSQLString();
}
  1. 从 hquery 中提取的查询参数映射,名称如“param0”、“param1”等。

我目前的挑战:

  1. 我提取的 SQL 字符串与执行原始查询期间输出的休眠日志记录完全相同。它有利于记录,但不适用于实际执行 - 它有问号 (?) 而不是名称参数(如:param0)或顺序(如?1)。我宁愿获得 Hibernate 生成的实际查询,而不必替换我的代码中的问号,也不必担心生成的 JPA/Hibernate 查询字符串中的潜在问号。有什么方法可以获取 SQL,因为它会去 JDBC 进行实际的 DB 请求?

  2. 我仍然需要将请求结果映射到实体结构。我不能只要求 Hibernate 返回此请求所针对的实体,因为生成的查询的字段别名与实体字段到表列的映射完全不同。因此,我需要将请求结果映射作为本机 SQL JPA 或 Hibernate 请求将接受作为映射的对象,或者作为将获取原始查询结果列表并返回实体对象列表的函数。我如何获得(更准确地说,从 Hibernate 结构中提取)这样的请求结果映射?

【问题讨论】:

  • 查看实体图和命名实体图。您可以指定它应该加载的内容并为您的子实体指定子图。
  • 实体图已经应用,它们限制了要加载的实体,我需要限制连接实体的字段(以及这些字段的相应数据库列)。

标签: java hibernate jpa


【解决方案1】:

您真正需要的是 DTO 模型,我认为这是 Blaze-Persistence Entity Views 的完美用例。

我创建了该库以允许在 JPA 模型和自定义接口或抽象类定义模型之间轻松映射,例如 Spring Data Projections on steroids。这个想法是您按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。

使用 Blaze-Persistence Entity-Views 的示例 DTO 模型可能如下所示:

@EntityView(User.class)
public interface UserDto {
    @IdMapping
    Long getId();
    String getName();
    Set<RoleDto> getRoles();

    @EntityView(Role.class)
    interface RoleDto {
        @IdMapping
        Long getId();
        String getName();
    }
}

查询是将实体视图应用于查询的问题,最简单的就是通过 id 进行查询。

UserDto a = entityViewManager.find(entityManager, UserDto.class, id);

Spring Data 集成让您可以像使用 Spring Data Projections 一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

Page<UserDto> findAll(Pageable pageable);

最好的部分是,它只会获取实际需要的状态!

【讨论】:

    猜你喜欢
    • 2017-11-27
    • 1970-01-01
    • 1970-01-01
    • 2014-10-26
    • 1970-01-01
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 2011-10-05
    相关资源
    最近更新 更多