簡體   English   中英

使用spring data jpa保存和更新實體父子的最佳方法

[英]Best way to save and update entity Parent and child using spring data jpa

我面臨一些關於 spring data jpa 的行為,我需要了解。

考慮一下:

文檔


@Getter
@Setter
@ToString
@Entity
@Table(name = "document")
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Document{

    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;
    private String title;
    private String description;

    @OneToMany(cascade = ALL, fetch = FetchType.LAZY, mappedBy = "document")
    @ToString.Exclude
    private Set<Template> templates = new HashSet<>();

    public void addTemplates(Template template) {
        templates.add(template);
        template.setDocument(this);
    }
}

模板

@Getter
@Setter
@ToString
@Entity
@Table
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Template{

    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;
    private String name;

    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "document")
    private Document document;
    
}

服務

@RequiredArgsConstructor
@Service
@Transactional
@Slf4j
public class DocumentService {

  private final DocumentRepository documentRepository;

  private final TemplateRepository templateRepository;


     public void createTemplate() {
        Set<Template> template = new HashSet<>();
        template.add("template1");
        template.add("template2");
        templateRepository.saveAll(template);
    }

public void createMovie(DocumentDTO documentRequest) {

        Set<Template> templates = toTemplate(documentRequest.getTemplates());
        Document document = Document.builder()
                .title(documentRequest.getTitle())
                .description(documentRequest.getDescription())
                .template(new HashSet<>())
                .build();
        templates.forEach(document::addTemplates);
        documentRepository.save(document);

    }

    private Set<Template> toTemplate(TemplateDTO templatesDTO) {
        return documentRequest.getTemplates().stream().map(templateDTO ->
                Template.builder()
                        .id(templateDTO.getId())
                        .firstName(templateDTO.getFirstName())
                        .lastName(templateDTO.getLastName())
                        .build()
       ).collect(Collectors.toSet());
    }

}

首先=>我創建了模板,例如當我創建一個新文檔時

{
    
    "title": "tre",
    "description": "opppp",
    "template": [
        {
            "id": 1,
            "name": "template1"
        },
        {
            "id": 2,
            "name": "template2",
        }
    ]
}

使用此數據配置,我將這個錯誤detached entity passed to persist 因此,為了解決此錯誤,我將 CASCADE Merge 改為 ALL 放在 Parent 上,如下所示

@OneToMany(cascade = MERGE, fetch = FetchType.LAZY, mappedBy = "document")
    @ToString.Exclude
    private Set<Template> template= new HashSet<>(); 

我再次嘗試保存文檔。 文檔沒問題,但模板中沒有任何反應。 這是控制台中的 sql

Hibernate: insert into document (id, description, title) values (null, ?, ?)

為什么孩子沒有更新文件ID?? 因為 spring jpa 調用的實體管理器持久化而不是 merge

有沒有辦法保存而不必顯式調用合並??? 因為如果我調用合並,我會在更新之前得到一堆選擇子項。 那么我該如何避免這個問題。

幾個觀察,當存在雙向映射時,子實體處的 JoinColumn 注釋是不必要的。

始終依賴 persist、persistAndFlush 或 persistAllAndFlush 而不是保存,因為它僅在存在新實體時才會持久,否則它將嘗試合並。 在這里您可以看到生成的 SQL 語句僅在父實體上而不是在子實體上。

參考, https://vladmihalcea.com/best-spring-data-jparepository/

我認為是幫助了一些人。 請關注弗拉德博客。 他解釋了為什么我們需要添加版本來避免多重選擇。 https://vladmihalcea.com/jpa-persist-and-merge/

所以在我的情況下,我在我的子實體中添加了這樣的想法:

    @Version
private Long version;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM