Dynamic Entity Graphs in Spring Data JPA

JPA and its implementation, Hibernate, is the most popular way to access relational data in Java applications. From the very beginning, data access optimization has been one of the main goals of Hibernate developers. One such optimization is eliminating unnecessary database queries, which significantly impact performance. For example, when dealing with related entities, such as master-detail relationships, we need to decide whether we need to fetch details. The simplest solution would be to mark associated entity fields with the EAGER fetch type. However, this is highly ineffective since we don’t always need associated entities. While LAZY fetching helps to avoid extra queries, it is essential to remember to fetch additional detail entities strictly within the transaction. Also, this may cause the N+1 query problem.

The Entity Graph specification was introduced in JPA 2.1, offering developers fine-grained control over how entities and their related data are fetched from the database. With entity graphs, developers can define explicit fetch plans, reducing the N+1 query problem and eliminating the need for manual JOIN clauses. This feature empowers developers to optimize data retrieval efficiently.

Testing Applications With JPA Buddy and Testcontainers

Testing is a cornerstone of any application lifecycle. Integration testing is a type of testing that helps to ensure that an application is functioning correctly with all of its external services, such as a database, authorization server, message queue, and so on. With Testcontainers, creating such an environment for integration testing becomes easier. However, setting just the environment is not enough for proper testing. Preparing test data is also an essential task. In this article, we will review the process of preparing application business logic tests. We will see how to set up Testcontainers for the application and explain some challenges we can meet during test data preparation.
JPA Buddy Graphic looking at Testcontainers, Spring Boot, JUnit5, and PostgreSQL

This article also has a companion video that guides you through the process of application testing with Testcontainers and JPA Buddy.

An Entity to DTO

What Is DTO?

Let’s start with the definition of DTO. According to Martin Fowler, DTO is: “An object that carries data between processes in order to reduce the number of method calls. When you're working with a remote interface, such as Remote Facade, each call to it is expensive. As a result, you need to reduce the number of calls... The solution is to create a Data Transfer Object that can hold all the data for the call.”
So, initially, DTOs were intended to be used as a container for remote calls. In a perfect world, DTOs should not have any logic inside and be immutable. We use them only as state holders. Nowadays, many developers create DTOs to transfer data between application layers, even for in-app method calls. If we use JPA as a persistence layer, we can read an opinion that it is a bad practice to use entities in the business logic, and all entities should be immediately replaced by DTOs.

We recently introduced DTO support in the JPA Buddy plugin. The plugin can create DTOs based on JPA entities produced by data access layer classes and vice versa – create entities based on POJOs. This allowed us to look at DTOs closer and see how we can use them on different occasions. For the sake of simplicity, we assume that we use Spring Data JPA to persist data and Spring Framework as the main framework in all our examples.

How to Store Text in PostgreSQL: Tips, Tricks, and Traps

DDL generation based on JPA entities definition is a daily task for many developers. In most cases, we use tools like Hibernate's built-in generator or JPA Buddy plugin. They make the job easier, but there are exceptions. When it comes to storing big chunks of data in the database, things get a bit complicated.

Use Case: Storing Documents 

Let’s assume we need to store a document object with its content in the PostgreSQL database. The JPA entity code for this might look like the code below:

Synchronization Methods for Many-To-Many Associations

The many-to-many association is a common thing in data modeling. In JPA entities, it is implemented as collections that store associated entities from the other side of the association. To keep collections consistent on both sides, developers usually implement data synchronization methods. This article will highlight common issues that happen when adding synchronized methods for many-to-many bidirectional associations in JPA entities.

Many-To-Many Bidirectional Associations: Why Synchronize?

Before speaking about sync methods, let's look at bidirectional associations and their implementation in JPA in detail. Imagine a blog application where we can mark every post with several tags. We can make two JPA entities for this application: Post and Tag with appropriate attributes like ID, text, etc. Now we need to establish the association between one post and many tags. To do this, let's define a tags attribute on the Post entity, the type of this attribute is Set<Tag>. Notice that each tag can be reused for more than one post. In this case, we can create the posts attribute of type Set<Post> in the Tag entity. This is the bidirectional many-to-many association: we have references to several entities on both sides of the association. And now, our data model looks like this:

The Ultimate Guide on Client-Generated IDs in JPA Entities

ID generation in the client instead of the database is the only option for distributed apps. But generating unique IDs in such apps is hard. And it's essential to generate them properly because JPA will use IDs to define entity states. The safest option is to use UUIDs and Hibernate's generators, but there are more options starting from custom generators to dedicated ID generation servers.

In the previous article, we discussed server-generated IDs for JPA entities. All the ID generation strategies described in the article are based on one fundamental principle: there is a single point that is responsible for generating IDs: a database. This principle might become a challenge: we depend on a particular storage system, so switching to another (e.g., from PostgreSQL to Cassandra) might be a problem. Also, this approach does not work for distributed applications where we can have several DB instances deployed on several data centers in several time zones. 

Database Lifecycle in Jmix: Migration Challenges

Introduction

In Jmix, the JPA data model, hence database is a cornerstone of the application.

In the case of software development, the principle “if it works, don’t touch it” does not always work. Software changes are inevitable, database migrations too. And, if a database update goes wrong, you can lose data, which is one of the most valuable things for the business.

The Data Access Layer in Jmix: JPA on Steroids

JPA with Jmix

Introduction

The data model is one of the cornerstones of any enterprise application. When you start planning the model, you should not only take into account business data requirements but also answer some additional questions that may affect your application design. For example: do you need row-based security? Are you going to use soft delete? Do we need CRUD API and who will do this boring job?

JPA is a de-facto standard for creating a data model for Java applications. This API does not provide facilities to implement advanced security or soft delete, so developers have to implement their own solutions.

Jmix: The Future of the CUBA Platform

Introduction

CUBA started its way back in 2008. Since then it went through a few very important stages. At first, it was an internal framework with no documentation and even less API. It was a company-wide thing that allowed Haulmont to develop Business Applications faster.

In 2015 CUBA was introduced world-wide under a proprietary license. We got just a few users that year — that was embarrassing. It became obvious that the licensing policy should be switched to open source.

CUBA: Getting Ready for Production

“It works on my local machine!” Nowadays it sounds like a meme, but the problem of development environment vs. production environment still exists. As a developer, you should always keep in mind that your application will start working in the production environment one day. In this article, we will talk about some CUBA-specific things that will help you to avoid problems when your application will go to production.

Coding Guidelines

Prefer Services

Almost every CUBA application implements some business logic algorithms. The best practice here is to implement all business logic in CUBA Services. All other classes: screen controllers, application listeners, etc. should delegate business logic execution to services. This approach has the following advantages:

Fetching Data With ORMs Is Easy! Is It?

Introduction

Almost any system operates with external data stores in some way. In most cases, it is a relational database and very often data fetching is delegated to some ORM implementations. ORM covers a lot of routine operations and brings along a few new abstractions in return.

Martin Fowler wrote an interesting article about ORM and one of the key thoughts there is “ORMs help us deal with a very real problem for most enterprise applications... They aren't pretty tools, but then the problem they tackle isn't exactly cuddly either. I think they deserve a little more respect and a lot more understanding.”