A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance

A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance: com.sample1.hibernate.User.address; nested exception is org.hibernate.HibernateException: A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance: com.sample1.hibernate.User.address

You probably see this error in one to many relationship in hibernate.

Lets say we have one to many relationship between the 2 entity.

User has one or more address.

User is defined as –>

public void setAddress(List<Address> address) { this.address = address; }

@Cascade( {CascadeType.ALL, CascadeType.DELETE_ORPHAN})
@OneToMany(mappedBy = “user”, fetch = FetchType.LAZY)
@JoinColumn(name=”user_id”)
public List<Address> getAddress() { return address; }

Address is defined as –>

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = “user_id”)
public User getUser() { return user; }

public void setUser(User user)  { this.user = user; }

Use case is we want to delete all the existing addresses for the user and add a new set of addresses to the user. So wrote below code to achieve this.

User user = loadUserByLogin(“shri”);

// remove all the existing addresses.
user.getAddress().clear();

// add new address
Address newAddress = new Address();
newAddress.setIndex1(6L);
newAddress.setUser(user);
newAddress.setAddress(“test”);
saveAddress(newAddress);

List<Address> addresses = new ArrayList<Address>();
addresses.add(newAddress);
user.setAddress(addresses);
saveUser(user);

When the transaction commits, you see said error in the log. There couple of ways you will be able to fix this –>

1. Instead of attaching new address list to the user, Add the addresses to existing address list that are already associated with user.

// remove all the existing addresses.
user.getAddress().clear();

// add new address
Address newAddress = new Address();
//newAddress.setId(2L); // required for oracle //ORA-01400: cannot insert NULL into (“SPATEL”.”ADDRESS”.”ID”)
newAddress.setIndex1(8L);
newAddress.setUser(user);
newAddress.setAddress(“test”);
saveAddress(newAddress);

List<Address> addresses = new ArrayList<Address>();
addresses.add(newAddress);
user.getAddress().addAll(addresses);
saveUser(user);

2. Link the address to user, but do not linking from user to address. Initial I thought this was wierd, but if you read way hibernate internal works, this will make sense.

// remove all the existing addresses.
user.getAddress().clear();

// add new address
Address newAddress = new Address();
newAddress.setIndex1(7L);
newAddress.setUser(user);
newAddress.setAddress(“test”);
saveAddress(newAddress);

saveUser(user);

Advertisements

2 thoughts on “A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance

  1. When I read in various places that hibernate didn’t like you to assign to a collection, I assumed that the safest thing to do would obviously be to make it final like this:

    class User {
    private final Set roles = new HashSet();

    public void setRoles(Set roles) {
    this.roles.retainAll(roles);
    this.roles.addAll(roles);
    }
    }

    However, this doesn’t work, and you get the dreaded “no longer referenced” error, which is actually quite misleading in this case.

    It turns out that hibernate calls your setRoles method AND it wants its special collection class installed here, and won’t accept your collection class. This had me stumped for a LONG time, despite reading all the warnings about not assigning to your collection in your set method.

    So I changed to this:

    public class User {
    private Set roles = null;

    public void setRoles(Set roles) {
    if (this.roles == null) {
    this.roles = roles;
    } else {
    this.roles.retainAll(roles);
    this.roles.addAll(roles);
    }
    }
    }

    So that on the first call, hibernate installs its special class, and on subsequent calls you can use the method yourself without wrecking everything. If you want to use your class as a bean, you probably need a working setter, and this at least seems to work.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s