Don't Miss These Two Important Hibernate Tips
Tags: java, webdev, programming, tutorial
Published: 2021-11-01 18:40:56


## Avoid Bi-directional Relationships ☝️


In bi-directional relations we have to remember to set both ends of the relation to reference each other whenever we want to persist one of them.

If we don't one of the two ends will have a null reference to the other and we would mess up our data 😿

Moreover it's very uncommon for us to traverse relationships both ways.  


### Let's look at an example 👇

Say we have Order and OrderLine entities that have a one-to-many relationship.

  
**Let’s do it the bi-directional way 🚫**

   ```java
@Entity
@Table(name = "ORDERS")
@Data
public class Order{
	@Id
	@GeneratedValue
	Integer id;
	
	@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
	List<OrderLine> orderLines = new ArrayList<>();
}

@Entity
@Data
public class OrderLine
{
	@Id
	@GeneratedValue
	Integer id;

	@ManyToOne
	Order order;
}
```

So, to make sure we have both ends set up we need to

```java
Order order = new Order();

OrderLine orderLine = new OrderLine();
orderLine.setOrder(order);

order.getOrderLines().add(orderLine);

entityManager.persist(order);
```


**And now let’s do it the unidirectional way ✅**
```java
@Entity
@Table(name = "ORDERS")
@Data
public class Order{
	@Id
	@GeneratedValue
	Integer id;

	@OneToMany(cascade = CascadeType.ALL)
	@JoinColumn(name = "ORDER_ID")
	List<OrderLine> orderLines = new ArrayList<>();
}

@Entity
@Data
public class OrderLine
{
	@Id
	@GeneratedValue
	Integer id;
}
```
  

Doing the following should persist both entities.
```java
Order order = new Order();

OrderLine orderLine = new OrderLine();

order.getOrderLines().add(orderLine);

entityManager.persist(order);
```

---

## Limit Relationships Via Numeric IDs ☝🏾


For entities that have different contexts, represent the relationship between them using Ids and not actual classes.

Say we have an OrderLine entity and a Product entity.

```java
@Entity
@Data
public class OrderLine
{
	@Id
	@GeneratedValue
	Integer id;

	@ManyToOne
	Product product;
}
  
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class Product
{
	@Id
	@GeneratedValue
	Integer id;
}
```

In this case if we fetch an OrderLine object then the Product will be fetched eagerly as well because the default behavior of `ManyToOne` is an `EAGER` fetch 🏃🏽‍♂️

Plus BDD principals says we should keep the Product and OrderLine entities separate from each other because they belong to different contexts.

The best way is to include Product in OrderLine as an ID.

### Example time 🏋🏽‍♂️
```java
@Entity
@Data
public class OrderLine
{
	@Id
	@GeneratedValue
	Integer id;
	  
	Integer productId;
}
```
And the code to set the product ID would be like:

```java
Product product = new Product();  
entityManager.persist(product);  
  
Order order = new Order();  
  
OrderLine orderLine = new OrderLine();  
order.getOrderLines().add(orderLine);  
orderLine.setProductId(product.getId());  
  
entityManager.persist(order);
```

---
## Credits 🙌🏾
This post was made mainly derived from Victor Rentea's [Designing Expressive and Performant Persistence Models for Relational DBs](https://www.youtube.com/channel/UC_RV_tw0mK1aStb6h1eX77g).