Sheldon
Sheldon

Reputation: 391

How do you remove rows after changing the item in a JPA OneToOne relationship?

How do you get a OneToOne item to automatically remove with JPA/Hibernate? I would expect simply setting the OneToOne item to be null in the class that contains would be smart enough to allow Hibernate to delete it.

Given a simple object, simplified:

@Entity
public class Container {
    private Item item;

    @OneToOne(cascade=CascadeType.ALL)
    public Item getItem() { return item; }

    public void setItem(Item newItem) { item = newItem; }
}

When an Item is set on Container an Container is persisted with merge a row gets inserted.

Container container = new Container();
container.setItem(new Item());
container = entityManager.merge(container);
// Row count is 1

But when the item is set null, or to another item, the old object still exists in the table.

container.setItem(null);
container = entityManager.merge(container);
// Row count is STILL 1, leaving orphaned rows.

So, how do I remove these OneToOne orphans?

Upvotes: 3

Views: 4043

Answers (4)

Jacob van Lingen
Jacob van Lingen

Reputation: 9537

As JPA 2.0 has been released for a very long time now, you could simply use:

@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)

Upvotes: 1

Miguel Ping
Miguel Ping

Reputation: 18347

I'm guessing that the reasone behind hibernate not allowing DELETE_ORPHAN to OneToOne relations is related to this issue.

If you really want this bad, you can hack your way with these steps:

  • transform your OneToOne relation into a OneToMany:
  • add a method just to get the first element of the child's collection (this is optional but handy)
  • use the DELETE_ORPHAN annotation

Of course, this is a big hack.

Upvotes: 1

Henning
Henning

Reputation: 16311

Unfortunately, there is no way to do this in JPA without tying yourself to Hibernate's implementation.

So yes, as Foxy says, you can use org.hibernate.annotations.CascadeType instead of the standard JPA annotation, which allows you to specify DELETE_ORPHAN. If you want to use the JPA abstraction, you must delete orphans yourself as of yet.

Upvotes: 0

FoxyBOA
FoxyBOA

Reputation: 5846

Try to change to

@OneToOne
@Cascade(cascade = {CascadeType.ALL, CascadeType.DELETE_ORPHAN})

See also my answer on similar post here.

Upvotes: 0

Related Questions