DEV Community

Cover image for [Quick Fix] Hibernate: object references an unsaved transient instance
Mateus Malaquias
Mateus Malaquias

Posted on

[Quick Fix] Hibernate: object references an unsaved transient instance

TL;DR

You are likely trying to save an Entity that refers to another object that isn't saved in the database yet.

The Fix: just add cascade = CascadeType.ALL to the relationship annotation.

// In your Parent Entity (e.g. Order.java)
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL) // <--- Add this
private List<OrderItem> items = new ArrayList<>();
Enter fullscreen mode Exit fullscreen mode

The Scenario

Here is the thing. You have an Order and a list of OrderItems. Classic relationship.

You create the Order, create an OrderItem, add the item to the list, and try to save the Order parent:

Order order = new Order();
order.setCustomer("John Doe");

// Creating a new child entity
OrderItem item = new OrderItem();
item.setProduct("MacBook Pro");
item.setOrder(order);

order.getItems().add(item);

// Trying to save
orderRepository.save(order);
Enter fullscreen mode Exit fullscreen mode

Boom. Exception.

The Error

The logs will scream this at you:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
Enter fullscreen mode Exit fullscreen mode

Why this happens

Basically, Hibernate is confused.

You have the OrderItem in memory (Java heap), but it doesn't exist in the DB yet (no ID). When you call .save(order), Hibernate looks at the child object and freaks out because it doesn't know if it should save that child automatically or not.

It stops the process to prevent data corruption. Ideally, it expects you to save the child manually first, but nobody wants to do that for every single item.

The Solution

We gotta tell JPA to just propagate the save operation.

Go to your Parent entity and force the cascade.

Before (The Error):

@Entity
public class Order {
    // ...
    @OneToMany(mappedBy = "order")
    private List<OrderItem> items = new ArrayList<>();
}
Enter fullscreen mode Exit fullscreen mode

After (The Fix):

@Entity
public class Order {
    // ...
    // The Fix: Add CascadeType.ALL
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> items = new ArrayList<>();
}
Enter fullscreen mode Exit fullscreen mode

Why this works

Adding CascadeType.ALL tells Hibernate: "If i save the Parent, save the Children too. If i delete the Parent, delete the Children."

Simple as that. Now when you run repository.save(order), Hibernate handles the new OrderItem insert automatically.

Note: If you are on legacy XML configs (I hope not), use cascade="all".

Top comments (0)