AndrewBourgeois
AndrewBourgeois

Reputation: 2765

Move an entity to another list

I'm trying to move an entity (JPA) from one list to another list.

The problem is that the entity gets deleted instead of being moved (in the database).

The model (simplified):

@Entity
public class Group {
    @Id
    @GeneratedValue
    @Column(name = "Id")
    private long id;
    @OneToMany(mappedBy = "group", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Item> items;

    public Group() {
        this.items = new ArrayList<>();
    }

    public List<Item> getItems() {
        return items;
    }

    public long getId() {
        return id;
    }
}

@Entity
public class Item {
    @Id
    @GeneratedValue
    @Column(name = "Id")
    private long id;
    private Group group;

    public Item() {
    }

    public Group getGroup() {
        return group;
    }

    public void setGroup(Group group) {
        this.group = group;
    }

    public long getId() {
        return id;
    }
}

The move operation is performed this way:

oldGroup.getItems().remove(item);
item.setGroup(newGroup);
newGroup.getItems().add(item);

Debugging shows that the lists are correctly updated but JPA is somehow unable to detect that the entity is used somewhere else and only cares about the CascadeType.ALL and orphanRemoval = true.

Note: it works when moving an entity from the first group to the second group but not the opposite.

Upvotes: 2

Views: 1055

Answers (2)

Didier L
Didier L

Reputation: 20608

From the definition of OneToMany:

/**
 * (Optional) Whether to apply the remove operation to entities that have
 * been removed from the relationship and to cascade the remove operation to
 * those entities.
 * @since Java Persistence 2.0
 */
boolean orphanRemoval() default false;

So I'm afraid that as soon as you remove the entity from the relationship, it is scheduled to be removed.

If you want to keep the orphanRemoval and avoid this issue, you could simply do the change on the Item side without altering the collection:

item.setGroup(newGroup);

without getItems().remove/add(item).

If you really need to update the collection, you might detach the oldGroup before performing the change in the collection.

Notice though that if you are in the context of a web app, this is usually not a problem if your URL's are RESTful:

  1. the client sends a POST to perform the change;
  2. the server performs the change and replies with a redirect;
  3. the client follows the redirect, which reloads the entity from database.

Upvotes: 1

JB Nizet
JB Nizet

Reputation: 692121

orphanRemoval = true means: if the entity is removed from the list, delete it. So it's precisely what you do not want to happen.

So just remove that attribute from your annotation (or set it to false).

Upvotes: 1

Related Questions