I have a situation where an entity could use another entity, and it could be used by another, so i have defined a ManyToMany relation that reference the same entity, so i could have listUse and listUsedBy, and both are persisted in the same table entity_usage :
@ManyToMany @JoinTable(name = "entity_usage", joinColumns = { @JoinColumn(name = "id_use", referencedColumnName = "id")}, inverseJoinColumns = { @JoinColumn(name = "id_used_by", referencedColumnName = "id")}) private List<Entity> listUse; @ManyToMany @JoinTable(name = "entity_usage", joinColumns = { @JoinColumn(name = "id_use_by", referencedColumnName = "id")}, inverseJoinColumns = { @JoinColumn(name = "id_use", referencedColumnName = "id")}) private List<Entity> listUsedBy;
Exemple : Entity A could use Entity B and C, so Entity B and C are used by A. Now my problem is when i add B and C to listUse, they are persisted in entity_usage, but when try to display listUsedBy i have to redeploy my project, otherwise listUsedBy remains empty, is there a way to refresh listUsedBy when persist my entity without having to redeploy my project.
1 Answers
Answers 1
This is the general approach:
@Entity public class SomeEntity { @ManyToMany @JoinTable(name = "entity_usage", joinColumns = @JoinColumn(name = "using_id"), inverseJoinColumns = @JoinColumn(name = "used_by_id")) private Set<SomeEntity> using = new LinkedHashSet<>(); @ManyToMany(mappedBy = "using") private Set<SomeEntity> usedBy = new LinkedHashSet<>(); public void addUsing(SomeEntity entity) { this.using.add(entity); entity.usedBy.add(this); } public void addUsedBy(SomeEntity entity) { this.usedBy.add(entity); entity.using.add(this); } }
and it's used:
public void someMethod(long parentEntityId, long childEntityId) { EntityManager em = getSomeEntityManager(); SomeEntity parentEntity = em.find(SomeEntity.class, parentEntityId); SomeEntity childEntity = em.find(SomeEntity.class, childEntityId); parentEntity.addUsing(childEntity); }
typically this is a transactional EJB method.
Note that there's no need to em.merge
anything, since entities are already managed by em.find
. Anyway, whichever method you'll use to manage your entities (query, find, persist, merge), remember that's important to call addUsing
/addUsedBy
only when both entities are managed.
This is one of the main incoherences that ORM logic cannot handle by its own: you have to inform both entities (parent and child) of their relation.
It's not sufficient to set the relation only on one side - if you only say that A is parent of B, B still doesn't know who is its parent.
However, there exists alternative approaches, like setting only the owning side of the relation (parent.getChildren().add(child)
), flush, and refresh the child.
Nevertheless (as I experienced very well on my skin) the alternatives are very hard to handle in real world complex applications.
As a side note, I'd use Set
instead of List
for the relation, unless you need some kind of insertion-order.
0 comments:
Post a Comment