具有共享 ID 的 OneToOne 关系需要 child 了解 parent

OneToOne relation with shared id requires child to know about parent

我在使用 Spring 数据将下面提供的实体存储到数据库时遇到问题。 OneToOne 关系用于这两者之间。它仅在 parentObject 明确设置为 childObject 时有效。这不是一个很好的解决方案,因为我希望 child object 根本没有 parent。可不可以? 非常相关的问题已发布 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;
}
}

不过我实在不喜欢把parentObject设置成ChildObject:

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

这是共享 ID 的唯一方法吗?如果未明确设置 parentObject,则会抛出以下错误:

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]

因为你有双向关系(你在两边都有 OneToOne 注释)你需要在另一边保存关系每一边的引用,如果你不喜欢,你可以把关系变成单向通过从一侧删除引用和映射来建立关系。

您可以轻松地封装这些操作,从而不需要有问题的调用:实际上,您应该始终这样做,以便您的内存模型始终处于一致状态:

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);
    }
}

现在,您的域模型的客户端 API 不需要知道任何有关子到父的反向引用形式的信息。

ChildObject childObject = new ChildObject("name");
ParentObject parentObject = new ParentObject(12L, childObject); //all relationships now set correctly