spring JPA entities: cheat sheet
Tags: springboot, jpa, beginners, learning
Published: 2024-04-28 20:58:11

Week 10 of coding bootcamp was marked by lots of junk food, a sleepless Sunday night from drinking my coffee too late, and oh yeah learning about Spring JPA entities. Learning them felt like mental gymnastics for me. Now that my brain has shakily landed from its endless flips and rumination, I wanted to share my basic understanding of the how behind each. 😅

![Flipping For Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cue98d923cll2btmhgrm.jpg)


## Table of Contents
1. 🌸 [One to Many](https://dev.to/ashleyd480/spring-jpa-entities-cheat-sheet-bbe#one-to-many)

2. 🌷 [One to One](https://dev.to/ashleyd480/spring-jpa-entities-cheat-sheet-bbe#one-to-one)

3. 🌼 [Many to Many](https://dev.to/ashleyd480/spring-jpa-entities-cheat-sheet-bbe#many-to-many)

---
<a id="One To Many"></a>
## One to Many
Below we have two entities from the basic backend framework of an ecommerce’s app’s backend. A customer has a one to many relationship with orders.  In other words, a customer can buy multiple orders.


![One to Many Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54625k3a3stxilcz8tru.png)

| Order | Customer |
|------------------|---------------------|
| `@ManyToOne` annotation above `private Customer customer` indicates many `Order` instances can belong to one `Customer` instance. | `@OneToMany` annotation above `private List<Order>  orders` means that one `Customer` instance can have multiple `Order` instances. |
| `@JoinColumn` indicates the foreign key of `customer_id` references the one in Customer table. `nullable=false` means that each order must have a customer instance (when being created/updated), or in other words belong to a customer. | `mappedBy= "customer"` (written above `List<Order> orders`) means that the list of orders is mapped to each customer via the `Customer customer` field on the Orders table (aka… the Orders table owns the relationship). |
| Hibernate then fetches the associated `Customer` instance based on that foreign key. This is how the order(s) are associated with the respective customer. | Remember how in the Order table, Hibernate gets the `Customer` instance via the foreign key and that is how it’s associated with those orders? |

*Note:  Even though we don’t see a list of orders or the  customer object - we can access that relationship programmatically via JPA, as discussed above.

Here are how the Order and Customer Table look respectively on Postgres.

![One to Many Tables](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mmemtdnk9e7tnu6bs7ra.png)


### @JsonIgnore
The `@JsonIgnore` is to prevent “looping” (aka circular dependency)  when we display the data. For example, when we made a request to get orders tied to a customer, without JSON, it would show the order, then the customer, which then shows the customer field info and then calls the order field which then calls the customer, ad infinitum. 

With `@JsonIgnore`- only the Order information would show when making that `get` request. 
When deciding where to place `@JsonIgnore`- you can think of it as we don’t need to show the customer when querying orders, but it would be more helpful to show the orders when querying a customer. An alternative way of approaching that thought process is: we put `@JsonIgnore` over the `customer` field, because a customer can exist without orders but not vice versa. 


### Owning Table
Orders is the owning table, which means any changes to the relationship,  such as adding or removing orders for a customer, should be made through the customer field in the Order entity.)  The owning side is also where the relationship is persisted in the database; that is the owning side is the one that owns the foreign key in the relationship.  

We chose orders as the owning side, because of operational logic. You typically create orders and associate with customers, not the other way around. 

The example code block shows how we add an order to a customer. `order` represents the new order we are adding (sent via the request body in the API call ` @PostMapping("/customers/{id}/orders")`). 
```
 public Customer addOrderToCustomer(Integer id, Order order) throws Exception {
        Customer customer = customerRepository.findById(id).orElseThrow(() -> new Exception("Customer not found"));
        order.setCustomer(customer);
        orderRepository.save(order);
        return customer;
    }
```

Notice how the updates in the code are done via the order’s side.  The customer that has made the order is set to the customer field in the Order entity. This `Order` instance that now has the respective customer tied to it is then saved (persisted) to the `Order` database. 


### Bidirectional 
As a side note, as cascade persist is not used above, you can set the order on the customer side as well to allow for bidirectional navigation. Cascade persist means that operations on say a customer entity would persist to the associated order entities (i.e. if you deleted a customer, then the associated customer would aso delete) …however, in our case- as we are primarily accessing orders from the orders side (i.e. we typically retrieve orders and associate them with customers), then we don’t need that bidirectional code added. 

#### Note:
Keep in mind, for unidirectional one-to-many relationships, in most cases- you have to set both entities "to each other", in other words for example set a team to a player, and player to a team. On the other hand, many-to-many relationships are bidirectional and that means if you set a post to have a tag, you don't need to set the post to the tag- since JPA handles that on the backend (made possible by the associations between both entities via the join table). 


---
<a id="One To One"></a>
## One to One
Below we see how each record in our Address entity is associated with one record in the Customer entity., and vice versa. That is, in our hypothetical scenario: each customer can have one address, and one address can belong to one customer. 


![One to One Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j9yapk7pm6l38l0wdzct.png)


All the annotations are handled on the Customer entity side: 
- `@OneToOne` annotation in our Customer entity above `private Address address` means that one customer instance has one address
- `CascadeType.ALL` in our Customer entity means that for any actions taken on a `Customer` instance, should also be applied to the `Address`. For example, if a customer is deleted, then its respective address will also be deleted. Likewise, if a customer is created, then it will be expected to have an address added. 
- `@JoinColumn` annotation indicates the `address_id` is the foreign key. 
- `nullable=false` means the `address_id` can’t be null, or in other words each customer needs to have an address associated with it. When creating or updating a user, it must have an address.
-`unique=true` means that for each customer, they must have a unique address. 

This screenshot below shows the Customer table in Postgres, and you can see the foreign key address_id as the first column- essentially allowing this table to “link” to the Address table. 


![One to One Table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9krj46g0x81xqc4gz133.png)


<a id="Many to Many"></a>
## Many to Many
Below we see a relationship where one order can have multiple products (i.e. TV, sofa, etc), and one product can have many orders. In other words, orders and products have a many to many relationship. 


![Many to Many Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hoowjqdd9lsxgav65ahs.png)

| Order | Product |
|------------------|--------------------|
| `@ManyToMany` above `List<Product>` means one order can have multiple products. |`@ManyToMany` above `List<Order>` means one product can have multiple orders. |
|`@JoinTable`is on the Order side. We query most from Orders and when we query, it allows the related products to properly display. |`@JsonIgnore` is placed over `List<Order>` to prevent that circular reference data loop. Also, we don't need a product result to show affiliated orders, whereas we want to show orders with their affiliated products. |
|`inverseJoinColumn` means the foreign key of `product_id` references the one in the Product table (opposite side table). Hibernate then fetches the associated `Product` instance based on that foreign key. This is how the orders(s) are associated with the respective products. | `mappedBy = “products”` means Orders is the owning side; you create Orders and associate products to orders. The list of orders is mapped to products via the Order table (through its join table). Remember how in the Order table, Hibernate gets the `Product` instance via the foreign key and that is how it’s associated with those orders? |

*This below screenshot shows the Join Table that is actually created in Postgres from that `@JoinTable` annotation. 

![Many to Many Diagram Table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nenvhngr614558yunidg.png)

Side note: 
- On the Order table: `=new ArrayList<>` initializes the list of products with an empty array list, so that as products are added to an order, that array list is updated. This ensures that the `products` field is not null even if no products are associated with that order at initialization time. 
- On the Product table: `=new ArrayList<>` initializes the list of orders with an empty array list, so that as new orders are made with that product, then those orders can be added in. This ensures that the `orders` field is not null even if no orders are associated with that product at initialization time.