[英]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.