0

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?

EasterBunnyBugSmasher
  • 1,507
  • 2
  • 15
  • 34

2 Answers2

0

Have a look at adding a @JoinColumn annotation to your @ManyToOne and the
javadocs for the @ManyToOne annotation.

Normally the mappedby would work the other way where the @OneToMany would be mappedby the @ManyToOne

redge
  • 1,182
  • 7
  • 6
  • the link doesn't work and the fact that the mappedBy works only the opposite is what I posted in my question. And I don't know how setting a JoinColumn will solve my problem. – EasterBunnyBugSmasher Jun 10 '15 at 18:52
  • @JoinColumn identifies the column of Element that is the foreign key to CompositeElement. – redge Jun 11 '15 at 10:48
  • I think you missed that I don't have a standard collecion on my "one" side but a map. I know I can have a OneToMany bidirectional relationship with the "many" side owning the relationship. And I know I can choose a database column with @JoinColumn. But if the "many" side owns the relationship, how do I set the key for the map entry? – EasterBunnyBugSmasher Jun 12 '15 at 19:10
  • You have already used @MapKeyColumn.What else do you need? Regardless of whether the logical domain model has the one side "owning" the relationship or not, in the Database, the many side owns the foreign key so it needs to sort of own the relationship in JPA implementation. You should still be able to have eager and lazy fetch as you wish. – redge Jun 13 '15 at 05:29
0

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.

EasterBunnyBugSmasher
  • 1,507
  • 2
  • 15
  • 34
  • You are obviously not telling us all of the story. The whole idea of re-ordering the children seems inconsistent with the use of a map. Please explain what you mean. – redge Jun 13 '15 at 07:41
  • There is also a @JoinTable annotation you could investigate that might let you do what you want. – redge Jun 13 '15 at 07:46
  • Why is re-ordering inconsistent with the use of map? Suppose you have a meeting agenda with different agenda items. And then you notice that you need to swap 2 of them. My point: The individual agenda items do not change when you swap their position on the agenda. Your point? – EasterBunnyBugSmasher Jun 15 '15 at 17:32
  • if you look at the initial question, you'll see that I used @JoinTable there. It's just not possible to have the key column in the JoinTable when the relationship is owned by the many side. – EasterBunnyBugSmasher Jun 15 '15 at 17:33