DEV Community

Philipp
Philipp

Posted on

One-to-Many and Many-to-Many in Spring Data JPA

Or better: Why I struggled to build my first own REST-API

Building a REST API is one of the basics in backend software developing, but I still hadn’t dealt with it yet. Thus, I was that guy who wasn’t on that party everyone talks about - I needed to change this.
Luckily, there are tons of opportunities to include a REST API in a project. My project is a portfolio website – also a thing fancy developers should have. Therefore, I started to read into that topic and structure my tech stack (Angular, Spring, Azure SQL Server).
For my backend I’ve chosen Spring, if you are familiar with it then you are probably already a fan of Baeldung – a perfect website to learn about the Spring Framework. They helped me a lot and without their guides and tutorials I wouldn’t be where I am now (my thesis was written in Spring Boot). So, Kudos to you guys!

But now to my REST API...

The data model is quite simple: a Project entity which can have several Skills that are used in it. Additionally, there is an Employment entity with details about the company and role.

Simplified Class Diagram

☝ --> 🖐

Between Employment and Project is a One-to-Many relationship. Nothing special – I just followed the tutorial on Baeldung. For these two entities I went with a bidirectional relationship, means that I am able to access Projects from Employments and Employments from Projects. For better understanding, I added my model classes in a shortened version below. Annotations like @Getter, @Setter and @Data are from Lombok - a nice little library to reduce boilerplate code.

Employment Class

In line 17 of Employment Class, you can see the @OneToMany annotation for field projects. The attribute mappedBy aims on field employment of my Project class. I could leave it like that, and it would work, but I want a bidirectional relationship. Therefore, the field employment of my Project class needs a @ManyToOne annotation as you can see below (Project Class).

Project Class

Until now it wasn’t a big deal except for one little recursion issue on my Employment entity, because of the fact, that my Json response of an Employment object includes the related Projects and these having an Employment object each with their Projects and so on. I tried to fix that issue by adding @JsonIgnore to field projects. However, by adding this annotation, a field or method is being “ignored by introspection-based serialization and deserialization functionality. That is, it should not be consider a ‘getter’, ‘setter’ or ‘creator’.” – according to the fasterxml documentation. Important to notice, that the whole projects field is ignored, so that we’re getting an Employment object in our response without any sign of the related projects. Oh dear, did I struggle with this annotation. At this point I was going in circles, cause my assumption was that I found the right annotation and was missing something else. After what felt like an eternity, I finally read about @JsonIgnoreProperties. Essentially the same but instead of ignoring the whole object, it is ignoring just individual fields/properties. In my case, it is ignoring the Employment field in my Project objects.
The recursion is gone and the One-to-Many relationship works fine. My next step was to implement a Many-to-Many relationship. So, I used my advanced Google techniques to find a good way to do it. 😎

Google Search

🖐 --> 🖐

There are several different approaches to handle the Many-to-Many relationship between Project and Skill. According to the tutorial on Baeldung you need to create a join entity class, if you want to add attributes to your relationship. Therefore, I added one for my join table ProjectSkills (see “Simplified Class Diagram”), because of the usageInPercentage attribute.
A join table primary key consists of foreign keys, a so-called composite key. In Spring you need to consider this for your join entity class. In figure ProjectSkills Class you might notice ProjectSkillsKey field with the @EmbeddedId annotation - that is our composite key. For the sake of completeness, I also attached the ProjectSkillsKey Class below. It simply combines our both foreign keys.

ProjectSkills Class

ProjectSkillsKey Class

Having a join entity class dissolves the Many-to-Many relationship and converts it into two separate One-to-Many relationships. Except for one small difference, this structure is identical to the relationship between Employment and Project. The difference: Another annotation is needed - @MapsId. It is used to indicate which the primary key of the annotated attribute is.
After implementing the ProjectSkills class, all needed relationships were portrayed. Thus, I was done with my entities. After all, I know, this is neither new nor exciting stuff, but it still gave me a good feeling to do it and write about it.

Thank you for your attention! Additionally, I am new to writing blogs, especially in English. Tips, tricks or language corrections are welcome! Many thanks in advance! ❤️

And don’t forget to add @JsonIgnoreProperties to avoid recursions!

Top comments (0)