使用MapStruct将新的子实体添加到托管实体中

问题描述 投票:0回答:1

我有一个REST端点,可用于创建或更新元素。这些元素的REST表示由Mapstruct映射到我的JPA实体。现在,为了更新现有实体,我将@MappingTarget传递给此方法:

@Mapping(source = "id", target = "id", ignore = true)
public abstract Element resourceToElement(ElementResource resource, @MappingTarget Element element);

实体Element与子实体具有一对多关系,我们就称它为Child。该关系在Element内部这样映射:

@OneToMany(cascade = ALL, mappedBy = "element", orphanRemoval = true, fetch = EAGER)
private Collection<Child> children = new ArrayList<>();

并且像在Child中一样,Element也是Child主键的一部分:

@ManyToOne(fetch = LAZY, optional = false)
@JoinColumn(name = "element_id")
@JsonManagedReference
@Id
private Element element;

现在由于JPA受管实体的性质,在从资源到实体的映射期间,在插入Child表期间出现以下错误:

NULL not allowed for column "ELEMENT_ID"

似乎是这种情况,因为Element已经是我要传入的托管实体,因此,只要我通过添加(非托管)子代来对其进行修改,它将尝试保留该元素。现在,我想我要做的就是将父项Element单独设置到每个子项中,以便它知道持久查询的element_id。但是在映射过程中的什么时候我会这样做?还是有一个更聪明的选择,我根本不需要这样做?

java spring jpa mapstruct
1个回答
0
投票

您可以通过使用@AfterMapping来实现。

@AfterMapping
protected void initializeChildElement(@MappingTarget Element element) {
    element.getChildren().forEach(child -> child.setElement(element));
}

或另一种方式正在使用@Context。有点复杂,但是它是在创建element之后立即设置Child字段,而不是遍历整个集合。

public Element resourceToElement(ElementResource resource, @MappingTarget Element element) {
    return resourceToElement(resource, element, element);
}

@Mapping(qualifiedByName = "ChildWithElement", target = "children")
protected abstract Element resourceToElement(ElementResource resource, @MappingTarget Element element, @Context Element context);

protected abstract Child childResourceToChild(ChildResource childResource);

@Named("ChildWithElement")
protected Child childResourceToChild(ChildResource childResource, @Context Element element) {
    Child child = childResourceToChild(childResource);
    child.setElement(element);
    return child;
}
© www.soinside.com 2019 - 2024. All rights reserved.