javajpabidirectional-relation

jpa map owned by the "one" side


I have a tree like data structure with some sort of composite pattern. With an abstract class Element, there is a CompositeElement and a SingleElement. It looks like this:

@Entity
@DiscriminatorValue("Composite")
public class CompositeElement extends Element {

  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinTable(name="Sub_Elements")
  @MapKeyColumn(name="xxx")
  protected Map<Integer, Element> subs;

  ...
}

Until now, the relation was unidirectional. It worked well. But now a use case popped up where I need to navigate from a sub element to the parent element. So what I'd love to do is this:

@Entity
@Inheritance
@DiscriminatorColumn("s_discriminator")
public class Element {

  @ManyToOne(mappedBy="subs", fetch=FetchType.LAZY)
  protected CompositeElement parent;
  ...
}

But the @ManyToOne Annotation doesn't allow a "mappedBy" attribute.

From a domain view, the parent owns the children objects in the data structure. Not the other way around. This is also emphasised by the eager fetch and the cascade rule.

If the ownership of the relationship was on the child side, then child.setParent(p) wouldn't really work because here I'm missing the key for the map.

Is there any way to keep the ownership of the relation on the side of the parent but still make it bidirectional?


Solution

  • it looks like it's not possible the way I want it.

    I changed it so the relationship is owned by the child. And I added a property "childIndex" in the Element class. This property is referenced by @MapKey.

    public class CompositeElement extends Element {
    
        @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="parent")
        @MapKey(name="childIndex")
        protected Map<Integer, Element> subs;
    

    and

    public abstract class Element {
    
        protected Integer childIndex;
    
        @ManyToOne(fetch=FetchType.LAZY)
        protected CompositeElement parent;
    

    The solution works, but I don't like it. I don't like the child element knowing its "childIndex". When I re-order the children in the parent object, I need to modify each of the children. I would have loved to keep a separate database table representing the relationship and the index column being there.

    I guess another option would have been to model the relation as an entity itself.