简体   繁体   English

Spring Data Jpa OneToMany 同时保存子实体和父实体?

[英]Spring Data Jpa OneToMany save child and parent entities at the same time?

This is my parent entity.这是我的父实体。 Note: Removing getters, setters, lombok annotations for brevity.注意:为简洁起见,删除 getter、setter、lombok 注释。

@Entity
public class Board {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @OneToMany(mappedBy = "board")
    private Set<Story> stories = new HashSet<>();
}

Below is my child entity下面是我的子实体

@Entity
public class Story {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "board_id")
    @JsonIgnore
    private Board board;
}

Each Board can have multiple Story , but each Story belongs to single Board .每个Board可以有多个Story ,但每个Story属于一个Board

Now somewhere in my service, I am doing this:现在在我的服务中的某个地方,我正在这样做:

public void addBoard(BoardDTO boardDto){
    // create a new board object which is just a pojo
    // by copying properties from boardDto
    Board board = ...;

    // create set of stories
    List<String> defaultTitles = Arrays.asList("Todo", "In-Progress", "Testing", "Done");
    Set<Story> stories = defaultTitles.stream().map(title -> Story.builder()
            .title(title)
            // assign a reference, I know this is wrong since board here is not
            // saved yet or fetched from db, hence the question
            .board(board) 
            .build())
            .collect(Collectors.toSet());

    // This saves board perfectly, but in Story db, the foreign key column
    // board_id is null, rightfully so since call to story table was not yet done.
    Board save = boardRepository.save(Board.builder()
            .title(board.getTitle())
            .stories(stories)
            .build());
}

One approach that I can take is to save the board first without Set<Story> and then do a save on stories with this saved board set as ref.我可以采取的一种方法是先在没有Set<Story>情况下保存板,然后使用此保存的板设置为参考对故事进行保存。 But this would need two Repository calls and code wise it wouldn't look good.但这需要两个 Repository 调用和代码明智的它看起来不太好。

Also, the reason why I am having trouble is because until I run this code, my db is empty.另外,我遇​​到问题的原因是因为在运行此代码之前,我的数据库是空的。 That is this is a new record that we are entering for the first time.这是我们第一次进入的新记录。 So Board table has no rows yet.所以Board table还没有行。

So is there anyway to do this in a single shot?那么有没有办法一次性做到这一点? For most of the other questions on stackoverflow, the board entity is already fetched from db and then they are adding child entities to it and saving it to db.对于 stackoverflow 上的大多数其他问题,板实体已经从 db 中获取,然后他们正在向其中添加子实体并将其保存到 db。 But for me, the db is completely fresh and I want to add a first new parent entity and its corresponding child entities at the same time, at least code wise even if hibernate makes multiple db calls.但对我来说,db 是全新的,我想同时添加第一个新的父实体及其相应的子实体,即使 hibernate 进行多个 db 调用,至少在代码方面也是如此。

Yes, you simply need to cascade the changes from the parent to the child:是的,您只需要将更改从父级级联到子级:

@Entity
public class Board {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    @OneToMany(mappedBy = "board", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Set<Story> stories = new HashSet<>();
}

Now whenever you save the parent ( Board ), the changes will cascade to the child table.现在,每当您保存父表 ( Board ) 时,更改都会级联到子表。 You can also use CascadeType.ALL instead of {CascadeType.PERSIST, CascadeType.MERGE} to cascade any changes, like removal (when you remove the child from the collection on the parent entity, the joining id in the child table will be removed).您还可以使用CascadeType.ALL而不是{CascadeType.PERSIST, CascadeType.MERGE}来级联任何更改,例如删除(当您从父实体的集合中删除子项时,子表中的连接 ID 将被删除) .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM