DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
11 Monitoring and Observability Tools for 2023
Learn more
  1. DZone
  2. Coding
  3. Java
  4. Architectural Miscalculation and Hibernate Problem "Type UUID but Expression Is of Type Bytea"

Architectural Miscalculation and Hibernate Problem "Type UUID but Expression Is of Type Bytea"

A story about how I tried to solve an architectural error with minimal code changes and what problems sometimes occur in popular libraries. So, let's go!

Artem Artemev user avatar by
Artem Artemev
·
Feb. 01, 23 · Tutorial
Like (6)
Save
Tweet
Share
2.65K Views

Join the DZone community and get the full member experience.

Join For Free

Nowadays, it is difficult to find a service that works on its own and does not communicate with other services, especially modern systems that are built on a microservice architecture. In this regard, there are difficulties in obtaining data from one or another service since not all the data necessary for the operation of the service is stored in one database, and you cannot simply make a "join." I want to talk about one of these problems and its solution in this article.

Case Description

A huge number of projects use Spring + Hibernate. This bundle gives an advantage in development speed, reducing the amount of code and blah blah blah. But there are also disadvantages.

Let's imagine the following situation; we have some entity "Document" which contains some fields among which there are (Id, Title, Author_id). And at the moment, the table with the authors' data is stored in the same database. We also have other services that store any entities with a link to the authors. As you may have guessed, the authors' data is difficult to keep up to date with this approach. They should be stored in a separate service that keeps them up to date.

Document Service

A simple Java code example of when data is stored in the same database:

 
@Entity
public class Author {

  @Id
  private UUID id;
...
 
public class Document {

  @Id
  private Integer id;
  @Column(name = "title")
  private String title;
  @Column(name = "author_id")
  @ManyToOne
  private Author author;
  ...


So, we need to edit the author field so that the data is filled not from the database of this service but from another service. Our database contains only the author's identifier.

Document service and User Service

The simplest thing that comes to mind is to declare the author field as a UUID and, after requesting this entity, convert it to a DocumentDto that will contain the author field as an object and enrich it from another source.

This option is suitable when there are few references to this field in the code, and you use REST.

In our case, GraphQL is used, there are many references to the Document entity and we do not need a DTO.

The most common solution is to use a converter.

Code Example

 
public class Author {
  private UUID id;
  private String firstname;
  private String lastname;
  ...


In class Document

 
@Column(name = "author_id")
@Convert(converter = AuthorConverter.class)
private Author author;


Converter

 
@Converter
public class AuthorConverter implements AttributeConverter<Author, UUID> {

  @Override
  public UUID convertToDatabaseColumn(Author author) {
    return author.getId();
  }

  @Override
  public Author convertToEntityAttribute(UUID id) {
    Author author = new Author();
    author.setId(id);
    return author;
  }
}


This is where the main problem lies if you use the UUID type as the identifier author.

When trying to save or modify the Document Entity in the database using the save method from JpaRepository, we will get an exception.

When using Hibernate-core 5.4.29. Final, the UUID is defined as a Varbinary type when converted and throws the following exception:

ERROR: column "author_id" is of type uuid but the expression is of type bytea.

Screenshot from debugger.

Screenshot from debugger.

When using Hibernate-core 5.6.14. Final, the UUID is defined as a Varchar type when converted and throws the following exception:

ERROR: column "author_id" is of type uuid but the expression is of type character varying.

After searching on Google, I came to the conclusion that many simply change the type from UUID to String and live with this solution. This is clearly a crutch and I do not like it.

The second crutch that I found in the code of my colleagues is to add one more field to the Document entity (oh my eyes), as shown below:

Code Example

 
@Column(name = "author_id", updatable = false, insertable = false)
@Convert(converter = AuthorConverter.class)
private Author author;

@Column(name = "author_id")
private UUID authorId;


This method can confuse other developers since it is not immediately clear which field the author to fill in when saving the entity.

In both cases, saving via the save method will work for you.

One way around this problem is to save and modify the entity with native queries. As soon as it came to mind, I checked it, and it works. However, although I love native queries, I don't like this option either because if you have many fields in the entity, then calling the save or change method with all these fields will look terrible.

Code Example

 
@Query(nativeQuery = true, value = "INSERT INTO public.document (title, author_id)"
    + " VALUES (?1, ?2)")
void insert(String title, UUID authorId);


The fourth crutch will work for Postgres. Since this database does not support the Varbinary type, you can change the type of this field in the database to Bytea. I have not tried this solution with Oracle DB.

Of all the above crutches, I would most likely choose the third one (native queries), but I do not like the code with crutches and I continued to think about solving the problem.

Having debugged the code a bit, I decided to go the other way and not use the converter. You can do without a converter by making the author a built-in entity (@Embedded), but since we use only the author's identifier to save in our database, the rest of the fields need to be moved to the superclass. Here is an example test code.

Sample Code

 
...
@Entity
public class Document {

  @Id
  private Integer id;

  @Column(name = "title")
  private String title;

  @Embedded
  @AttributeOverrides(@AttributeOverride(name = "id", column = @Column(name = "author_id")))
  private Author author;
}
 
...
@Embeddable
public class Author extends AuthorFields {

  private UUID id;

}
...
public class AuthorFields {

  private String firstname;
  private String lastname;
}


This method works great; no need to change the data type in the database or make native queries to save the data. However, this is where I stopped.

Conclusion

In this article, I tried to describe the existing problem and ways to solve it without unnecessary text.

Once again, I was convinced that you should not rush to the first solution that came across on StackOverflow, although all the solutions to this problem that I found there were to use String.

Perhaps this article will help someone and make life easier)

Thank you for your attention!

Database Hibernate Spring Data Java (programming language)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Use Java Event Listeners in Selenium WebDriver
  • Spring Cloud
  • DeveloperWeek 2023: The Enterprise Community Sharing Security Best Practices
  • A Deep Dive Into AIOps and MLOps

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: