![](/img/trans.png)
[英]ModelMapper & JPA: How to map DTO with id to Entity with oneToMany field
[英]ModelMapper: Error mapping ID field from DTO to the ID field on the Entity
我正在嘗試從具有 int 產品 ID 的 ProductReviewDTO 映射以鏈接到在 ProductReview 實體上找到的產品。 但是使用 ModelMapper 似乎無法正確映射。 導致設置值失敗錯誤消息以及 IllegalArgument 異常,說明在嘗試設置值時對象不是聲明類的實例。
ProductReview 到 ProductReviewDTO 的第一個映射工作正常。
DTO:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProductReviewDTO {
private int id;
private int productId;
}
實體:
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "product_reviews")
public class ProductReview {
@Id
@SequenceGenerator(name="product_reviews_generator", sequenceName = "product_reviews_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "product_reviews_generator")
@Column(name = "id", updatable = false, nullable = false)
private int id;
@ManyToOne(cascade=CascadeType.DETACH, fetch = FetchType.LAZY)
@JoinColumn(name = "product_id", nullable=false)
private Product product;
}
映射:
@NoArgsConstructor
public class ProductReviewMapping implements BaseMapping<ProductReview, ProductReviewDTO> {
@Override
public PropertyMap<ProductReview, ProductReviewDTO> MapFromSourceToTarget() {
return new PropertyMap<ProductReview, ProductReviewDTO>() {
protected void configure() {
map().setProductId(source.getProduct().getId());
map().setUserId(source.getUser().getId());
map().setRatingId(source.getRating().getId());
}
};
}
@Override
public PropertyMap<ProductReviewDTO, ProductReview> MapFromTargetToSource() {
return new PropertyMap<ProductReviewDTO, ProductReview>() {
protected void configure() {
map().setProduct(new Product().builder().id(source.getProductId()).build());
}
};
}
}
Caused by: org.modelmapper.MappingException: ModelMapper mapping errors:
1) Failed to set value '1' on com.pfex.ecom.library.common.entity.Product$ProductBuilder.id()
這是舊的,但沒有答案,問題仍然存在,所以我將提供我的解決方案。
我在使用 ModelMapper 時遇到了一個非常相似的問題。 問題本質上是 ModelMapper 不支持 PropertyMap 邏輯內部的 getter/setter 調用之外的任何復雜性(請參閱此鏈接)。 連三級算子都太多了。 這讓我感到困惑,但這是事實。
在 OP 的情況下,“MapFromTargetToSource”使用構建器的事實太復雜了。
我找到了 3 個選項來解決這個問題。 我在下面列出了它們以及每個 JUnit 示例。
(注意:我的 ModelMapper(2.4.4)版本中沒有 BaseMapping 類,所以我有一個更簡單的單向實現,但它的工作原理類似。在實踐中,我將 ModelMapper 的使用包裝在 Converter Objects 中所以這些選項都封裝在convert()接口方法后面。)
選項 1:您可以預先進行所有推導,並在 configure() 方法中設置一個簡單的值。
@Test
public void modelMapper_complexMapping_option_1_externalDerivation_so() {
ProductReviewDTO source = ProductReviewDTO.builder().id(123).productId(456).build();
ModelMapper mapper = new ModelMapper();
TypeMap<ProductReviewDTO, ProductReview> typeMap = mapper.typeMap(ProductReviewDTO.class, ProductReview.class);
Product derivedField = Product.builder().id(source.getProductId()).build();
PropertyMap<ProductReviewDTO, ProductReview> targetToSource = new PropertyMap<>() {
protected void configure() {
map().setProduct(derivedField);
}
};
typeMap.addMappings(targetToSource);
ProductReview actual = mapper.map(source, ProductReview.class);
assertThat(actual.getId(), is(source.getId()));
assertThat(actual.getProduct().getId(), is(source.getProductId()));
}
選項 2:您可以在源類中編寫一個內部方法來派生該值。 根據用例、組織標准等,這可能有意義,也可能沒有意義。恕我直言,對於像 OP 正在使用的 DTO 來說,這沒有意義,但在其他情況下可能。
@Test
public void modelMapper_complexMapping_option_2_internalDerivation_so() {
ProductReviewDTO source = ProductReviewDTO.builder().id(123).productId(456).build();
ModelMapper mapper = new ModelMapper();
TypeMap<ProductReviewDTO, ProductReview> typeMap = mapper.typeMap(ProductReviewDTO.class, ProductReview.class);
PropertyMap<ProductReviewDTO, ProductReview> targetToSource = new PropertyMap<>() {
protected void configure() {
map().setProduct(source.synthesizeProduct());
}
};
typeMap.addMappings(targetToSource);
ProductReview actual = mapper.map(source, ProductReview.class);
assertThat(actual.getId(), is(source.getId()));
assertThat(actual.getProduct().getId(), is(source.getProductId()));
}
public class ProductReviewDTO {
private int id;
private int productId;
public Product synthesizeProduct() {
return Product.builder().id(getProductId()).build();
}
}
選項 3:您可以使用 ModelMapper 的“使用轉換器”語法。 我覺得這很笨重,但它確實有效。 這是一個參考。
@Test
public void modelMapper_complexMapping_option_3_usingConverter_so() {
ProductReviewDTO source = ProductReviewDTO.builder().id(123).productId(456).build();
ModelMapper mapper = new ModelMapper();
TypeMap<ProductReviewDTO, ProductReview> typeMap = mapper.typeMap(ProductReviewDTO.class, ProductReview.class);
PropertyMap<ProductReviewDTO, ProductReview> targetToSource = new PropertyMap<>() {
protected void configure() {
using(new Converter<ProductReviewDTO, Product>() {
public Product convert(MappingContext<ProductReviewDTO, Product> context) {
ProductReviewDTO src = context.getSource();
return Product.builder().id(src.getProductId()).build();
}
}).map(source).setProduct(null);
}
};
typeMap.addMappings(targetToSource);
ProductReview actual = mapper.map(source, ProductReview.class);
assertThat(actual.getId(), is(source.getId()));
assertThat(actual.getProduct().getId(), is(source.getProductId()));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.