The best way to use Java Records with JPA and Hibernate

栏目: IT技术 · 发布时间: 5年前

内容简介:In this article, I’m going to show you how you can useJava Records with JPA and Hibernate.Added since version 14 as a preview feature, Java Records allow us to create compact DTOs (Data Transfer Objects) or Value Objects.Let’s assume we have the following
Last modified:

Imagine having a tool that can automatically detect if you are using JPA and Hibernate properly. Hypersistence Optimizer is that tool!

Introduction

In this article, I’m going to show you how you can useJava Records with JPA and Hibernate.

Added since version 14 as a preview feature, Java Records allow us to create compact DTOs (Data Transfer Objects) or Value Objects.

Domain Model

Let’s assume we have the following Post entity class in our application:

The best way to use Java Records with JPA and Hibernate

Notice that the Post entity uses theFluent-style API, which allows us to build entity instances like this:

entityManager.persist(
    new Post()
        .setId(1L)
        .setTitle("High-Performance Java Persistence")
        .setCreatedBy("Vlad Mihalcea")
        .setCreatedOn(
            LocalDateTime.of(2016, 11, 2, 12, 0, 0)
        )
        .setUpdatedBy("Vlad Mihalcea")
        .setUpdatedOn(
            LocalDateTime.now()
        )
);
entityManager.persist(
    new Post()
        .setId(2L)
        .setTitle("Hypersistence Optimizer")
        .setCreatedBy("Vlad Mihalcea")
        .setCreatedOn(
            LocalDateTime.of(2020, 3, 19, 12, 0, 0)
        )
        .setUpdatedBy("Vlad Mihalcea")
        .setUpdatedOn(
            LocalDateTime.now()
        )
);

Can Java Records be used as JPA or Hibernate entities?

One very common question is if Java records are going to simplify the way we are building JPA or Hibernate entities. And, the answer is no. They will not.

According to the JPA specification, an entity must follow these requirements:

  • the entity class needs to be non- final ,
  • the entity class needs to have a no-arg constructor that is either public or protected ,
  • the entity attributes must be non- final .

However, as explained bythis article, the Java Record type is defined like this:

final
final

So, a Java Record cannot be used as an entity.

More, even if Hibernate relaxed these requirements, a Java Record would defeat the purpose of translating entity state transitions into SQL statements.

 A Java Record is not suitable to be used as a JPA or Hibernate entity. 

Using Java Records as DTOs

Let’s assume we have the following PostInfo and AuditInfo DTO classes:

The best way to use Java Records with JPA and Hibernate

With Java Records, we can define the AuditInfo like this:

public record AuditInfo(
    LocalDateTime createdOn,
    String createdBy,
    LocalDateTime updatedOn,
    String updatedBy
) {}

and the PostInfo looks as follows:

public record PostInfo(
    Long id,
    String title,
    AuditInfo auditInfo
) {}

Now, to use the simple class name instead of the fully-qualified one in JPQL queries, we are going to register the AuditInfo and PostInfo Java Records using the ClassImportIntegrator provided by the Hibernate Types project :

properties.put(
    "hibernate.integrator_provider",
    (IntegratorProvider) () -> Collections.singletonList(
        new ClassImportIntegrator(
            Arrays.asList(
                AuditInfo.class,
                PostInfo.class
            )
        )
    )
);

For more details about the ClassImportIntegrator utility, check outthis article.

Using Java Records in JPA constructor expression queries

To fetch an AuditInfo DTO projection for a given Post , we can use the following JPQL query:

AuditInfo auditInfo = entityManager.createQuery("""
    select 
        new AuditInfo (
            p.createdOn,
            p.createdBy,
            p.updatedOn,
            p.updatedBy
        )
    from Post p
    where p.id = :postId
    """, AuditInfo.class)
.setParameter("postId", 1L)
.getSingleResult();

Thanks to multiline Java Text Blocks , the JPQL query is very straight-forward.

While you can also fetch the AuditInfo using as @SqlResultSetMapping , neither the JPQL constructor Expression nor the the @SqlResultSetMapping allows you to fetch the PostInfo as you need to pass a properly instantiated AuditInfo reference in the PostInfo constructor.

Using Java Records using the Hibernate ResultTransformer

Where JPA falls short, Hibernate comes to the rescue. Thanks to the [ ResultTransformer](https://vladmihalcea.com/hibernate-resulttransformer/) Hibernate feature, you can fetch the PostInfo and AuditInfo` Java Records together:

List<PostInfo> postInfos = entityManager.createQuery("""
    select 
        p.id,
        p.title,
        p.createdOn,
        p.createdBy,
        p.updatedOn,
        p.updatedBy
    from Post p
    order by p.id
    """)
.unwrap(Query.class)
.setResultTransformer(
    (ListResultTransformer) (tuple, aliases) -> {
        int i =0;
        return new PostInfo(
            ((Number) tuple[i++]).longValue(),
            (String) tuple[i++],
            new AuditInfo(
                (LocalDateTime) tuple[i++],
                (String) tuple[i++],
                (LocalDateTime) tuple[i++],
                (String) tuple[i++]
            )
        );
    }
)
.getResultList();

Thanks to the ListResultTransformer utility, that’s also offered by the amazing Hibernate Types project , we can use a Java Lambda function to define the Hibernate ResultTransformer logic.

For more details about DTO projections with JPA and Hibernate, check outthis article.

I'm running an online workshop on the 14th of May about The Best Way to Fetch Data with Java Persistence and Hibernate .

The best way to use Java Records with JPA and Hibernate

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

The best way to use Java Records with JPA and Hibernate The best way to use Java Records with JPA and Hibernate

Conclusion

So, while Java Records are not suitable for mapping JPA and Hibernate entities, they are very useful for DTO projections.

Fetching DTOs is a very common requirement for read-only data that needs to be feed to the UI layer, so Java Records can ease the process of defining DTO projections.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

代码大全(第2版)

代码大全(第2版)

[美] 史蒂夫·迈克康奈尔 / 金戈、汤凌、陈硕、张菲 译、裘宗燕 审校 / 电子工业出版社 / 2006-3 / 128.00元

第2版的《代码大全》是著名IT畅销书作者史蒂夫·迈克康奈尔11年前的经典著作的全新演绎:第2版不是第一版的简单修订增补,而是完全进行了重写;增加了很多与时俱进的内容。这也是一本完整的软件构建手册,涵盖了软件构建过程中的所有细节。它从软件质量和编程思想等方面论述了软件构建的各个问题,并详细论述了紧跟潮流的新技术、高屋建瓴的观点、通用的概念,还含有丰富而典型的程序示例。这本书中所论述的技术不仅填补了初......一起来看看 《代码大全(第2版)》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

html转js在线工具
html转js在线工具

html转js在线工具