0

I have a problem while storing below provided entity to the database using Spring data. OneToOne relation is used between those two. It works only when parentObject is explicitly set to childObject. This is not a nice solution as I would like that child object didn't have parent at all. Is it possible or not? The very related question is posted here

@Entity
@Table(name = "parent_object")
public class ParentObject {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Long id;

@Column(name = "age")
private Long age;

@OneToOne(cascade = CascadeType.ALL, mappedBy = "parentObject")
private ChildObject childObject;

public ParentObject() {
}

public ParentObject(Long age, ChildObject childObject) {
    this.age = age;
    this.childObject = childObject;
}

public Long getId() {
    return id;
}

public Long getAge() {
    return age;
}

public ChildObject getChildObject() {
    return childObject;
}

public void setChildObject(ChildObject childObject) {
    this.childObject = childObject;
}
}

@Entity
@Table(name = "child_object")
public class ChildObject {
@Id
@Column(name = "child_id", unique = true, nullable = false)
private Long id;

@MapsId
@OneToOne
@JoinColumn(name = "child_id")
private ParentObject parentObject;

@Column(name = "name")
private String name;

public ChildObject() {
}

public ChildObject(String name) {
    this.name = name;
}

public Long getId() {
    return id;
}

public ParentObject getParentObject() {
    return parentObject;
}

public String getName() {
    return name;
}

public void setParentObject(ParentObject parentObject) {
    this.parentObject = parentObject;
}
}

However, I really don't like to set parentObject to ChildObject:

ChildObject childObject = new ChildObject("name");
ParentObject parentObject = new ParentObject(12L, childObject);
childObject.setParentObject(parentObject);

Is this the only way to have shared id? If parentObject is not set explicitly, then following error is thrown:

Caused by: org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [test.ChildObject.parentObject]
    at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:83) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
Community
  • 1
  • 1
Vytautas Arminas
  • 387
  • 5
  • 16
  • I have deleted parentObject field from ChildObject class, added @JoinColumn(name = "child_id") private ChildObject childObject to parentObject and removed mappedBy. I probably missed something because after given suggestions following error is thrown: Caused by: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): – Vytautas Arminas Apr 13 '17 at 12:17

2 Answers2

1

Since you have bidirectional relation ( you have OneToOne annotation at both sides) you need to hold a reference of each side of the relation in the other side, if you do not like that you can turn the relation into a unidirectional relation by removing the reference and the mapping from one side.

Amer Qarabsa
  • 6,412
  • 3
  • 20
  • 43
  • Ok, the purpose is get working unidirectional relation. In child class @Id @Column(name = "child_id", unique = true, nullable = false) private Long id; And in parent class: @OneToOne(orphanRemoval = true, cascade = CascadeType.ALL) @JoinColumn(name = "child_id") private ChildObject childObject; But the error is aused by: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save() – Vytautas Arminas Apr 13 '17 at 12:21
  • if the relation is unidirectional you should not have reference in each side of the relation, for example to make the relation unidirectional from ParentObject to ChildObject you need to remove the ParentObject reference in the ChildObject – Amer Qarabsa Apr 13 '17 at 18:21
1

You can easily encapsulate the operations so that the problematic call is not required: indeed, you should always do this in order that your in-memory model is always in a consistent state:

public class ParentObject{

    public ParentObject(Long age, ChildObject childObject) {
        this.age = age;
        this.childObject = childObject;

        childObject.setParentObject(this);
    }

    public void setChildObject(ChildObject childObject) {
        this.childObject = childObject;
        childObject.setParentObject(this);
    }
}

Now, a client of your Domain Model API does not need to know anything about the back-reference form Child to Parent.

ChildObject childObject = new ChildObject("name");
ParentObject parentObject = new ParentObject(12L, childObject); //all relationships now set correctly
Alan Hay
  • 22,665
  • 4
  • 56
  • 110