休眠级联顺序,ID生成和双向关系

时间:2019-03-11 17:46:27

标签: hibernate jpa orm

考虑以下三个具有各自关系的实体:

public class Project {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected UUID id;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "project", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Event> events = new HashSet<>();

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "project", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Entry> entries = new HashSet<>();
}
public class Event {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected UUID id;

    @ManyToOne(fetch= FetchType.LAZY)
    @JoinColumn(name="project_id")
    private Project project;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "event")
    protected Set<Entry> entries = new HashSet<>();
}
public class Entry {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    protected UUID id;

    @ManyToOne(fetch= FetchType.LAZY)
    @JoinColumn(name="project_id")
    private Project project;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="event_id", nullable=false)
    protected Event event;
}

现在,我有一个方法来获取带有事件作为输入的项目,并从中创建条目和其他事件。之后,它们都应保存。

我发现的主要挑战是:

  • (1)由于 ID生成在数据库中,因此我无法将它们全部添加到项目中,然后保存条目。为了使双向关系保持同步,我需要先保存它们,然后添加,或者保存项目并在添加后级联条目。尤其是当我有一个已经保存的实体集合和尚没有PK的实体时,我需要清除整个集合的新设置,或者在添加它们之前保存这些实体。

  • (2)无级联顺序:在尝试保存项目并级联条目时,子实体不能具有相互依赖的关系。例如。如果尝试在保存事件之前保存条目怎么办?我找不到设置级联顺序的任何选项。

  • (3)进入事件之间的双向关系也需要保持同步。但是,有些事件是新添加的,而其他事件已经存在并已保存,对于新添加的事件,我们需要注意(1)。

问题是:如何做到最好?

我可以在创建时保存实体,但是每次创建时我都会有一个事务。或者,我可以将它们全部保留在结果对象中并保存到最后,然后将它们添加到项目中并保存项目。但是,这两个选项als都没有过多地使用层叠选项,并且非常复杂,因为它们添加了时间依赖性。 (先保存X,然后保存Y,然后再保存Z)


更新:编码我当前如何添加实体并将其保存到项目中

该项目具有帮助程序方法,该方法仅设置条目(可以设置双向关系,但是在创建条目/事件时不允许Project为null):

public void addEntries(Collection<Entry> entries){
        this.entries.addAll(entries);
    }


    public void addEvents(Collection<Event> events){
        this.events.addAll(events);
    }


    public void addEntry(Entry entry){
        this.entries.add(entry);
    }


    public void addEvent(Event event){
        this.events.add(event);
    }

当前,我正在保存创建时的事件以及仿真功能之后的条目。在所有操作之后,项目始终保存在最后。

    public ADEvent createADEvent(Round round) {
        ADEvent event = new ADEvent(round);
        event = saveDB ? eventRepository.save(event) : event;
        round.getProject().addEvent(event);
        return event;
    }

    public void saveEntries(Project project, Collection<Entry> entries) {
        if (saveDB) entries = entries.stream().map(entryRepository::save).collect(Collectors.toList());
        project.addEntries(entries);
    }

    public Project saveProject(Project project) {
        return saveDB ? projectRepository.save(project) : project;
    }

更新的方法相同,只是在运行模拟方法之前,我先清除了项目中的整个集合。 (并删除所有模拟事件)

1 个答案:

答案 0 :(得分:0)

我不会单独保存每个实体。如果与项目一起保存,则可能不会出现问题。级联定义正确,我能够将它们全部添加并保存project。只需确保建立了双方关系

    Project p = new Project();
    Entry ntry = new Entry();
    Event event = new Event();

    p.getEntries().add(ntry);
    ntry.setProject(p);// set also other side of relation
    ntry.setEvent(event);

    p.getEvents().add(event);
    event.setProject(p);// set also other side of relation
    event.getEntries().add(ntry);

    em.persist(p);