与SpringData JPA保持OneToOne关系

Dav*_*cía 8 spring persistence hibernate jpa spring-data-jpa

我有接下来的两个实体,它们之间有OneToOne关系:

@Entity
@Table(name = "tasks")
public class Task {
    @OneToOne(mappedBy = "task", cascade = CascadeType.PERSIST)
    private Tracker tracker;

    /* More code */
}

@Entity
@Table(name = "trackers")
public class Tracker {
    @OneToOne
    @JoinColumn(name = "trk_task", unique = true)
    private Task task;

    /* More code */
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试运行此代码:

Task task = taskService.findDispatchableTask();
if (task != null) {
    Tracker tracker = trackerService.findIdleTracker();
    if (tracker != null) {
        task.setTracker(tracker);
        task.setStatus(TaskStatus.DISPATCHED);
        taskService.save(task);
    }
}
Run Code Online (Sandbox Code Playgroud)

但我得到这个错误:

ERROR org.hibernate.AssertionFailure  - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session) 
org.hibernate.AssertionFailure: non-transient entity has a null id
Run Code Online (Sandbox Code Playgroud)

我可以"解决"它将我的代码更改为:

Task task = taskService.findDispatchableTask();
if (task != null) {
    Tracker tracker = trackerService.findIdleTracker();
    if (tracker != null) {
        tracker.setTask(task);
        trackerService.save(tracker);
        task.setTracker(tracker);
        task.setStatus(TaskStatus.DISPATCHED);
        taskService.save(task);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,坚持OneToOne关系的正确方法是什么?在我的代码中,为什么我要保存关系的两个部分以使其工作?

JB *_*zet 19

再来一次.

每个双向关联都有两个方面:所有者方和反方.反面是具有mappedBy属性的一面.业主方是另一方.JPA/Hibernate只关心所有者方面.因此,如果您只是初始化反面,则关联将不会持久化.

通常,初始化关联的两个方面是一种很好的做法.首先是因为它确保了所有者方面的初始化,其次是因为它使实体图形连贯,为了您自己的利益.

另请注意,如果您在事务内部工作(并且您应该),则查询返回的所有实体都是附加实体.在提交事务时(或之前),应用于实体的更改将自动保持持久性.没有必要像你一样明确地保存实体.

  • 交易的关键是能够原子地改变多种类型的多种实体.一切都得救了,或者什么都没有.这就是保证数据一致性的原因.这就是为什么服务应该是事务性的,而不仅仅是存储库.在事务中加载实体并在同一事务中修改它们后,Hibernate会自动保留更改,而无需明确保存它们.简而言之,您的问题中的所有代码都应该在事务服务方法中,您不必调用`save()`. (2认同)