将 JPA 或 Hibernate 投影查询映射到 DTO(数据传输对象)

2024-04-12

在我的 DAO 层中,我有一个像这样的 Find 函数

public List<?> findCategoryWithSentenceNumber(int offset, int maxRec) {
  Criteria crit = getSession().createCriteria(Category.class, "cate");
    crit.createAlias("cate.sentences", "sent");

    crit.setProjection(Projections.projectionList().
    add(Projections.property("title"), "title").
    add(Projections.count("sent.id"), "numberOfSentence").
    add(Projections.groupProperty("title"))
  );

  crit.setFirstResult(offset);
  crit.setMaxResults(maxRec);

  return crit.list();
}

因此,为了读取数据,我必须使用循环(带有Iterator)

List<?> result = categoryDAO.findCategoryWithSentenceNumber(0, 10);
// List<DQCategoryDTO> dtoList = new ArrayList<>(); 

for (Iterator<?> it = result.iterator(); it.hasNext(); ) {
  Object[] myResult = (Object[]) it.next();

  String  title = (String) myResult[0];
  Long count = (Long) myResult[1];


  assertEquals("test", title); 
  assertEquals(1, count.intValue()); 

  // dQCategoryDTO = new DQCategoryDTO();
  // dQCategoryDTO.setTitle(title);
  // dQCategoryDTO.setNumberOfSentence(count);
  // dtoList.add(dQCategoryDTO);

}

我的问题是:有没有什么api、框架可以轻松转换List<?> result到一个列表中DTO对象(例如 DQCategoryDTO)而不使用任何循环、迭代器和调用 setter/getter 来填充值?


您有很多选项可以将投影映射到 DTO 结果集:

使用 Tuple 和 JPQL 的 DTO 投影

List<Tuple> postDTOs = entityManager.createQuery("""
    select
        p.id as id,
        p.title as title
    from Post p
    where p.createdOn > :fromTimestamp
    """, Tuple.class)
.setParameter( "fromTimestamp", Timestamp.from(
    LocalDateTime.of(2016, 1, 1, 0, 0, 0)
        .toInstant(ZoneOffset.UTC )))
.getResultList();

assertFalse(postDTOs.isEmpty());
 
Tuple postDTO = postDTOs.get(0);
assertEquals( 
    1L, 
    postDTO.get("id") 
);

使用构造函数表达式和 JPQL 的 DTO 投影

List<PostDTO> postDTOs = entityManager.createQuery("""
    select new com.vladmihalcea.book.hpjp.hibernate.query.dto.projection.jpa.PostDTO(
        p.id,
        p.title
    )
    from Post p
    where p.createdOn > :fromTimestamp
    """, PostDTO.class)
.setParameter( "fromTimestamp", Timestamp.from(
    LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )
        .toInstant( ZoneOffset.UTC ) ))
.getResultList();

您还可以从 JPA 构造函数表达式中省略 DTO 包名称,并通过其简单的 Java 类名称引用 DTO(例如,PostDTO https://vladmihalcea.com/the-best-way-to-map-a-projection-query-to-a-dto-with-jpa-and-hibernate/).

List<PostDTO> postDTOs = entityManager.createQuery("""
    select new PostDTO(
        p.id,
        p.title
    )
    from Post p
    where p.createdOn > :fromTimestamp
      """, PostDTO.class)
.setParameter( "fromTimestamp", Timestamp.from(
  LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )
      .toInstant( ZoneOffset.UTC ) ))
.getResultList();

使用元组和本机 SQL 查询的 DTO 投影

Hibernate 5.2.11 中提供了这一功能,因此又多了一个升级的理由。

List<Tuple> postDTOs = entityManager.createNativeQuery("""
    SELECT
           p.id AS id,
           p.title AS title
    FROM Post p
    WHERE p.created_on > :fromTimestamp
    """, Tuple.class)
.setParameter( "fromTimestamp", Timestamp.from(
    LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )
        .toInstant( ZoneOffset.UTC ) ))
.getResultList();

使用 ConstructorResult 的 DTO 投影

如果我们使用相同的PostDTO之前介绍过的类类型,我们必须提供以下内容@SqlResultSetMapping:

@NamedNativeQuery(
    name = "PostDTO",
    query = """
        SELECT
               p.id AS id,
               p.title AS title
        FROM Post p
        WHERE p.created_on > :fromTimestamp
        """,
    resultSetMapping = "PostDTO"
)
@SqlResultSetMapping(
    name = "PostDTO",
    classes = @ConstructorResult(
        targetClass = PostDTO.class,
        columns = {
            @ColumnResult(name = "id"),
            @ColumnResult(name = "title")
        }
    )
)

现在,名为本机查询的 SQL 投影执行如下:

List<PostDTO> postDTOs = entityManager.createNamedQuery("PostDTO")
.setParameter( "fromTimestamp", Timestamp.from(
    LocalDateTime.of( 2016, 1, 1, 0, 0, 0 )
        .toInstant( ZoneOffset.UTC ) ))
.getResultList();

使用 ResultTransformer 和 JPQL 的 DTO 投影

这次,您的 DTO 需要具有 Hibernate 从底层 JDBC 填充的属性的设置器ResultSet.

DTO 投影如下所示:

List<PostDTO> postDTOs = entityManager.createQuery("""
    select
           p.id as id,
           p.title as title
    from Post p
    where p.createdOn > :fromTimestamp
    """)
.setParameter( "fromTimestamp", Timestamp.from(
    LocalDateTime.of( 2016, 1, 1, 0, 0, 0 ).toInstant( ZoneOffset.UTC ) ))
.unwrap( org.hibernate.query.Query.class )
.setResultTransformer( Transformers.aliasToBean( PostDTO.class ) )
.getResultList();

使用 ResultTransformer 和本机 SQL 查询的 DTO 投影

List postDTOs = entityManager.createNativeQuery("""
    select
           p.id as \"id\",
           p.title as \"title\"
    from Post p
    where p.created_on > :fromTimestamp
    """)
.setParameter( "fromTimestamp", Timestamp.from(
    LocalDateTime.of( 2016, 1, 1, 0, 0, 0 ).toInstant( ZoneOffset.UTC ) ))
.unwrap( org.hibernate.query.NativeQuery.class )
.setResultTransformer( Transformers.aliasToBean( PostDTO.class ) )
.getResultList();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 JPA 或 Hibernate 投影查询映射到 DTO(数据传输对象) 的相关文章

随机推荐

  • 如何处理 MVC 中的页面流(特别是 asp.net)

    如果您必须在 mvc 中提供类似于表单输入体验的向导 您将如何抽象页面流 研究重定向后获取模式 http weblogs asp net mhawley archive tags MVC default aspx http weblogs
  • sql 按日期分组,不带时间

    我是 sql 新手 我想创建一个查询来计算我每天的所有文章 ID 但问题是日期列也包含时间 那么我如何才能使查询仅按日期分组而无需时间 例如 id article id date timestamp 1 22 2014 01 10 13 3
  • GIT 不跟踪文件

    我已经在 AIX 6 1 上设置了 GIT 但遇到了问题 我遵循的步骤顺序如下所示 我创建一个文件夹 进入文件夹并初始化非裸存储库 初始化用户名和用户电子邮件 创建一个名为index html 的文件 并在该文件中包含一些数据 创建一个名为
  • 对小数的最快素数测试

    我在业余时间玩了 Euler 项目 现在我需要做一些重构 我已经实施了 Miller Rabin 以及一些筛子 我以前听说过 对于较小的数量 例如数百万以下 筛子实际上更快 有人有这方面的信息吗 谷歌并没有多大帮助 Yes you ll f
  • Tensorflow动态RNN(LSTM):如何格式化输入?

    我已获得这种格式的一些数据以及以下详细信息 person1 day1 feature1 feature2 featureN label person1 day2 feature1 feature2 featureN label person
  • 设置非 Office 文件的 Windows 文件属性

    我想在 NET 代码中设置文件的属性 我尝试过使用 DSOFile v2 1 如下所示 var properties new OleDocumentProperties try properties Open filePath proper
  • java中如何从字符串中提取子字符串

    亲爱的大家 我有一个像这样的字符串 1name john 2name lice 3name mike 我想输出它的子字符串 1name john 它在字符串中的位置不固定 我也使用子字符串方法但无法获取它 那么你能帮我一个忙吗 谢谢 Str
  • C# - 静态类型不能用作类型参数

    我有一个通用类可以帮助我检查参数值 internal sealed class Argument
  • Eclipse - 当涉及 Maven 时“作为 Java 应用程序运行”

    我有一个 Maven 项目 作为activeByDefault我有生产资料 看来我找不到使用临时配置文件在 Eclipse 中将其作为应用程序运行的方法 除非我将activeByDefault在暂存配置文件中 有没有办法配置这个 这样我就不
  • IE 脚本和通知设置之间的差异

    这些 IE 设置之间有什么区别 Disable script debugging Internet Explorer Disable script debugging Other Display a notification about e
  • 如何对这个(正确)抛出异常的异步方法进行单元测试?

    我在界面中有以下方法 Task
  • 使用 Javascript 进行速率限制并将 ajax 调用排队为每 15 秒一次

    我有一个应用程序 每次用户执行某些操作时都会自动发送推文 如果用户愿意 可以轻松地每秒执行一次该操作 Twitter 的速率限制表示 它关注 15 分钟内发生了多少条推文 从技术上讲 我认为我总是低于 15 分钟标记 但 Twitter 似
  • 如何处理 YARN MapReduce 作业的容器故障?

    YARN 中如何处理软件 硬件故障 具体来说 如果容器发生故障 崩溃 会发生什么 容器和任务失败由节点管理器处理 当容器失败或死亡时 节点管理器会检测到失败事件并启动一个新容器来替换失败的容器并在新容器中重新启动任务执行 如果应用程序主机发
  • 宏中参数的意外多重评估

    为什么第二个 printf 的输出是 max of 50 and 67 is 62 为什么 50 和 62 的最大值不是 57 define MAX a b a gt b a b int incr static int i 42 i 5 r
  • 无法使用实例引用访问成员“object.Equals(object, object)”;用类型名称来限定它

    当我在 C 中使用以下代码时 int totalValue 0 int total 0 totalValue int Parse Session price ToString int Parse Session day ToString T
  • TFS 合并:无法丢弃变更集

    我们有一个变更集 开发人员已签入对源分支和目标分支的更改 许多更改包括两个分支中的重命名 从源分支到目标分支的变更集合并进展顺利 但变更集仍保留在要合并的变更集列表中 当我现在尝试再次合并更改集时 它显示 没有要合并的更改 并且变更集保留在
  • 数组值不相同(但它们是?)

    我有两个数组 它们似乎包含至少一组相同的值 但执行array diff 即使我认为应该返回任何内容 也不会返回任何内容 这应该只是例行代码 但由于某种原因它不喜欢我所做的 奇怪的是var dump queue 0 回报String 167
  • 创建一个简单的 Makefile 来构建共​​享库

    我正在尝试创建一个非常基本的手工制作的 Makefile 来创建一个共享库来说明一点 这是我到目前为止所拥有的 SHELL bin sh CC gcc FLAGS std gnu99 Iinclude CFLAGS fPIC pedanti
  • JSON 请求发送空数据(swift)

    我的 iOS 应用程序正在向 Web 服务发送空数据 我花了几个小时寻找解决方案 但没有任何效果 应用程序应该通过 php 脚本将 kontrah 号码发送到数据库 然后数据库必须识别是否可以在数据库中找到 kontrah 编号 然后 如果
  • 将 JPA 或 Hibernate 投影查询映射到 DTO(数据传输对象)

    在我的 DAO 层中 我有一个像这样的 Find 函数 public List