gpt4 book ai didi

hibernate - 使用 mapstruct 映射 Hibernate 实体

转载 作者:行者123 更新时间:2023-12-03 23:15:42 28 4
gpt4 key购买 nike

我是这些技术的新手,所以提前道歉。

我在我的应用程序中使用 springboot、Spring JPA、hibernate 和 mapstruct。

我已插入 id 为“1”的父记录。现在,当我尝试为 parent 插入一个 child 时,它会抛出

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing :



那么我如何指示mapstruct生成代码,以便它获取父记录,插入创建一个新对象,我猜这会导致上述问题。
    /**
* Mapper class for the entity {@link Child} and its corresponding data transfer object {@link ParentTlDTO}.
*/
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.WARN, uses = {ParentMapper.class})
public interface ChildMapper extends EntityMapper<ChildDTO, Child> {

@Mapping(source = "parent.id", target = "parentId")
@Override
ChildDTO toDto(Child child);

@Mapping(source = "parentId", target = "parent.id")
@Override
Child toEntity(ChildDTO childDTO);

default Child fromId(String id) {
if (id == null) {
return null;
}
Child Child = new Child();
Child.setId(id);
return Child;
}
}


@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE, uses = {})
public interface ParentMapper extends EntityMapper<ParentDTO, Parent> {

@Mapping(target = "childs", ignore = true)
Parent toEntity(ParentDTO parentDTO);

default Parent fromId(String id) {
if (id == null) {
return null;
}
Parent parent = new Parent();
parent.setId(id);
return parent;
}
}

----- 模型类 ----
 @ApiModel(description = "Child holds the descriptive information of currencies translated into various languages supported by the application.")
@Entity
@Table(name = "child")
@Cache(usage = CacheConparentStrategy.NONSTRICT_READ_WRITE)
@Document(indexName = "child")
public class Child extends AbstractEntity {

private static final long serialVersionUID = 6419585975683709213L;

/**
* Identifier of the descriptive information.
*/
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid2")
@Column(name = "id", columnDefinition = "CHAR", length = 36, nullable = false)
private String id;

/**
* Name of the parent.
*/
@NotNull
@Size(min = 3, max = 120)
@Column(name = "entity_name", columnDefinition = "VARCHAR", length = 120, nullable = false)
private String entityName;

/**
* Brief description about the parent.
*/
@Size(max = 256)
@Column(name = "entity_desc", columnDefinition = "VARCHAR", length = 256, nullable = true)
private String entityDesc;

@ManyToOne(fetch = FetchType.EAGER)
@JsonIgnoreProperties("childs")
private Parent parent;

@ManyToOne(fetch = FetchType.EAGER)
private Language language;

/**
* Callback method that is triggered before persisting the descriptive information of the parent where default
* values are set for mandatory attributes and values are massaged without compromising on data integrity.
*/
@PrePersist
public void setDefaultValues() {
this.entityName = StringUtils.capitalize(StringUtils.trim(this.entityName));
this.entityDesc = StringUtils.trim(this.entityDesc);
}

/**
* @return the id
*/
public String getId() {
return id;
}

/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}

/**
*
* @return
*/
public String getEntityName() {
return entityName;
}

/**
*
* @param entityName
* @return
*/
public Child entityName(String entityName) {
this.entityName = entityName;
return this;
}

/**
*
* @param entityName
*/
public void setEntityName(String entityName) {
this.entityName = entityName;
}

/**
*
* @return
*/
public String getEntityDesc() {
return entityDesc;
}

/**
*
* @param entityDesc
* @return
*/
public Child entityDesc(String entityDesc) {
this.entityDesc = entityDesc;
return this;
}

/**
*
* @param entityDesc
*/
public void setEntityDesc(String entityDesc) {
this.entityDesc = entityDesc;
}

/**
*
* @return
*/
public Parent getParent() {
return parent;
}

/**
*
* @param parent
* @return
*/
public Child parent(Parent parent) {
this.parent = parent;
return this;
}

/**
*
* @param parent
*/
public void setParent(Parent parent) {
this.parent = parent;
}

public Language getLanguage() {
return language;
}

public Child language(Language language) {
this.language = language;
return this;
}

public void setLanguage(Language language) {
this.language = language;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Child child = (Child) o;
if (child.getId() == null || getId() == null) {
return false;
}
return Objects.equals(getId(), child.getId());
}

@Override
public int hashCode() {
return Objects.hashCode(getId());
}

@Override
public String toString() {
return "Child{"
+ "id=" + getId()
+ ", entityName='" + getEntityName() + "'"
+ ", entityDesc='" + getEntityDesc() + "'"
+ "}";
}
}



@ApiModel(description = "Parent class holds the primary definition of a parent such as parent code, parent symbol etc.")
@Entity
@Table(name = "parent")
@Cache(usage = CacheConparentStrategy.NONSTRICT_READ_WRITE)
@Document(indexName = "parent")
public class Parent extends AbstractEffectiveEntity {

private static final long serialVersionUID = 5671242791959882244L;

/**
* Identifier of the parent.
*/
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid2")
@Column(name = "id", columnDefinition = "CHAR", length = 36, nullable = false)
private String id;

/**
* Code assigned to the parent.
*/
@NotNull
@Size(min = 2, max = 5)
@Column(name = "parent_code", columnDefinition = "CHAR", length = 5, nullable = false, updatable = false)
private String parentCode;

/**
* Symbol associated with the parent.
*/
@NotNull
@Size(min = 2, max = 10)
@Column(name = "parent_symbol", columnDefinition = "VARCHAR", length = 10, nullable = false, updatable = false)
private String parentSymbol;

/**
* Flag to denote whether parent is installed in the product suite to support converting it to other currencies.
*/
@Column(name = "installed_flag", columnDefinition = "CHAR", length = 1, nullable = false)
private String installedFlag;

/**
* Bi-directional OneToMany is not the best and most efficient way to model a one to many relationship. But in this
* case we prefer to keep a collection of descriptive information (children) in Parent (parent) to retrieve the
* descriptive information via Parent, since the count of descriptive information shall be less (depending on the
* number of languages supported in the application for translation). Limitations of this are (1) inability to limit
* the number of descriptive information (Child) loaded and thus no support for pagination, (2) inability to sort
* descriptive information since @OrderColumn annotation can be expensive.
*/
@OneToMany(mappedBy = "parent")

@Cache(usage = CacheConparentStrategy.NONSTRICT_READ_WRITE)
private Set<Child> childs = new HashSet<>();

/**
* Callback method that is triggered before persisting the primary information of the parent where default values
* are set for mandatory attributes and values of key attributes are massaged without compromising on data integrity.
*/
@PrePersist
public void setDefaultValues() {
this.parentCode = StringUtils.upperCase(StringUtils.trim(this.parentCode));
this.parentSymbol = StringUtils.trim(this.parentSymbol);
this.installedFlag = StringUtils.upperCase(StringUtils.trim(this.installedFlag));
if (StringUtils.isBlank(this.installedFlag)) {
this.installedFlag = "N";
}
}

/**
* Returns the identifier of the parent.
*
* @return the parent identifier.
*/
public String getId() {
return id;
}

/**
* Sets the identifier of the parent.
*
* @param id the identifier to be set for the parent.
*/
public void setId(String id) {
this.id = id;
}

/**
* Returns the code associated with the parent.
*
* @return the parentCode
*/
public String getParentCode() {
return parentCode;
}

/**
* Sets the code associated with the parent.
*
* @param parentCode the parentCode to set
*/
public void setParentCode(String parentCode) {
this.parentCode = parentCode;
}

/**
* Sets the code of the parent in the Parent object.
*
* @param parentCode
* @return parent the Parent object with parentCode set.
*/
public Parent parentCode(String parentCode) {
this.parentCode = parentCode;
return this;
}

/**
* Returns the symbol associated with the parent.
*
* @return the parentSymbol
*/
public String getParentSymbol() {
return parentSymbol;
}

/**
* Sets the symbol associated with the parent.
*
* @param parentSymbol the parentSymbol to set
*/
public void setParentSymbol(String parentSymbol) {
this.parentSymbol = parentSymbol;
}

/**
* Sets the symbol of the parent in the Parent object.
*
* @param parentSymbol
* @return parent the Parent object with parentSymbol set.
*/
public Parent parentSymbol(String parentSymbol) {
this.parentSymbol = parentSymbol;
return this;
}

/**
* Return true if the parent is marked as installed in the product suite, otherwise false.
*
* @return the installedFlag
*/
public String getInstalledFlag() {
return installedFlag;
}

/**
* Setter method to specify whether the parent is marked as installed in the product suite or not.
*
* @param installedFlag the installedFlag to set
*/
public void setInstalledFlag(String installedFlag) {
this.installedFlag = installedFlag;
}

/**
* Sets the flag to denote whether the parent is installed in the product suite or note in the Parent object.
*
* @param installedFlag
* @return the Parent object with installedFlag set.
*/
public Parent installedFlag(String installedFlag) {
this.installedFlag = installedFlag;
return this;
}

/**
*
* @return
*/
public Set<Child> getChilds() {
return childs;
}

/**
*
* @param childs
* @return
*/
public Parent childs(Set<Child> childs) {
this.childs = childs;
return this;
}

/**
*
* @param child
* @return
*/
public Parent addChild(Child child) {
this.childs.add(child);
child.setParent(this);
return this;
}

/**
*
* @param child
* @return
*/
public Parent removeChild(Child child) {
this.childs.remove(child);
child.setParent(null);
return this;
}

/**
*
* @param childs
*/
public void setChilds(Set<Child> childs) {
this.childs = childs;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Parent parent = (Parent) o;
if (parent.getId() == null || getId() == null) {
return false;
}
return Objects.equals(getId(), parent.getId());
}

@Override
public int hashCode() {
return Objects.hashCode(getId());
}

@Override
public String toString() {
return "Parent{" + "id=" + getId() + ", parentCode='" + getParentCode() + "'" + ", parentSymbol='"
+ getParentSymbol() + "'" + ", installedFlag='" + getInstalledFlag() + "'" + "}";
}

}

最佳答案

您正在寻找的可能类似于 Passing the mapping target type to custom mapperslookup-entity-by-id例子。

您可以拥有一个抽象映射器,您可以在其中注入(inject)存储库并执行实体查找。或者您甚至可以将存储库作为 @Context 传递范围。

假设您有 ParentRepository在里面你有findById(String id)
所以不要使用 ParentMapper在您的 ChildMapper您将使用 ParentRepository .然后 MapStruct 将生成如下代码:

@Component
public class ChildMapperImpl implements ChildMapper {

@Autowired
private ParentRepository parentRepository;

@Autowired
private ChildFactory childFactory;


@Override
public Child toEntity(ChildDTO childDTO) {
Child child = childFactory.create(childDTO);

child.setParent(parentRepository.findById(childDTO.getParentId());
}
}

您当然需要将映射调整为 @Mapping(source = "parentId", target = "parent")ChildMapper#toEntity方法。

如果您想获取实体进行更新,您需要使用 Object Factory .您需要输入 ChildFactory在子映射器中也使用注释。

例如,为了获取 child 以执行更新,您可以使用以下内容:
public class ChildFactory {

protected final ChildRepository childRepository;

public ChildFactory(ChildRepository childRepository) {
this.childRepository = childRepository;
}

@ObjectFactory
public Child create(ChildDTO childDTO) {
Child child = childRepository.findById(childDTO.getId());
return child == null ? new Child() : child;
}
}

关于hibernate - 使用 mapstruct 映射 Hibernate 实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51129128/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com