繁体   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