DEV Community

Cover image for Don't Miss These Two Important Hibernate Tips
Abdulcelil Cercenazi
Abdulcelil Cercenazi

Posted on

Don't Miss These Two Important Hibernate Tips

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 🚫

@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;
}
Enter fullscreen mode Exit fullscreen mode

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

Order order = new Order();

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

order.getOrderLines().add(orderLine);

entityManager.persist(order);
Enter fullscreen mode Exit fullscreen mode

And now let’s do it the unidirectional way ✅

@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;
}
Enter fullscreen mode Exit fullscreen mode

Doing the following should persist both entities.

Order order = new Order();

OrderLine orderLine = new OrderLine();

order.getOrderLines().add(orderLine);

entityManager.persist(order);
Enter fullscreen mode Exit fullscreen mode

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.

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

    @ManyToOne
    Product product;
}

@Entity
@NoArgsConstructor
@AllArgsConstructor
public class Product
{
    @Id
    @GeneratedValue
    Integer id;
}
Enter fullscreen mode Exit fullscreen mode

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 🏋🏽‍♂️

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

    Integer productId;
}
Enter fullscreen mode Exit fullscreen mode

And the code to set the product ID would be like:

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);
Enter fullscreen mode Exit fullscreen mode

Credits 🙌🏾

This post was made mainly derived from Victor Rentea's Designing Expressive and Performant Persistence Models for Relational DBs.

Top comments (0)