Pregunta

Say you have a unidirectional one-to-many association from class A to class B, like this:

public class A {
    @OneToMany(cascade = CascadeType.ALL)
    private List<B> myBs;
}

public class B {
    //I know nothing about A
}

In the database, these are connected through a third table, keeping their id's.

Now, I would like to delete a B-object, that is connected to an A. A has its own repository class, and B has its own repository class.

The way this has been done in similar settings in my project, is to first ask the A in question to remove the B in question, and then telling the EnitityManager to remove the B from the database.

This makes me a bit stuck between two choices, where neither of them are optimal in my mind:

  1. The repository method in BRepository handles both the removal of B from the A its connected to, and the removal from the database through the EntityManager. I don't like this, because then B's repository-class will have to manipulate A-objects.

  2. The repository method in BRepository only deals with removal through the EntityManager, leaving it up to the caller to remove it from A's collection. I like this even less, because if someone were to call the repository without first removing the B from A's collection, it will fail horribly.

Of the two I find the first to be by far the best. But still, I don't really think that it's clean.

Is there some construct in Hibernate that allows for the item to be deleted to be removed from any collection it is part of, upon removal from the database? (Trying to just delete the B fails because the A containing it is also loaded in the same transaction, so it fails upon the end of the transaction, when it's trying to store something that is deleted.)

(Would adding mappedBy on the @OneToMany-mapping in A solve the problem?)

¿Fue útil?

Solución

I've found a way to solve this, through the use of orphan deletion.

By changing the mapping in A to this:

public class A {
   @OneToMany(cascade = CascadeType.ALL)
   @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
   private List<B> myBs;
}

I can just say

a.getMyBs().remove(b);

and b will be deleted upon a being persisted.

Otros consejos

Step outside of the Hibernate mind set and ask yourself: Who owns Bs?

Owners are ultimately responsible for their property. Usually, this is true when there can't be a B without an A and each B is owned by exactly one A.

So if the As own the Bs, ARepository is responsible to clean the Bs up. I would create a method in ARepository that does the cleanup and which calls the delete method in BRepository.

If you truly want to keep the repositories separate the other option is to create a service class on top that is aware of both and will handle removals for you in a similar manner to your option 1 approach.

(Would adding mappedBy on the @OneToMany-mapping in A solve the problem?)

I think this depends on he repository implementation. For JPA EntityManager if the session is closed A will be detached when you delete B even if it is a bi-directional mapping.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top