如何将 DTO 映射到多个实体?

How to map a DTO to multiple entities?

我正在编写一个 Spring 应用程序,它有两个通过一对多关系关联的实体,我们称它们为母亲和孩子。

当我通过 POST 请求创建母实体时,我希望自动创建子实体。使用@OneToMany 和@ManyToOne 注释,效果很好。至少,只要我在 MotherService 中提供孩子的信息。

这是我的代码

Mother.java

@Entity
@Table(name="mother")
public class Mother{
   @Id
   @Column(name="id", updatable = false, nullable = false)
   private Long id;

   @Column(name="name")
   private String name;

   @OneToMany(mappedBy = "mother", cascade = CascadeType.ALL, orphanRemoval = true)
   private List<Kid> kidList = new ArrayList<>();

   //constructor, getter, setter

   private void addKid(Kid kid) {
      this.kidList.add(kid);
      kid.setMother(this);
   }
}

Kid.java

@Entity
@Table(name="kid")
public class Kid{
   @Id
   @Column(name="id", updatable = false, nullable = false)
   private Long id;

   @Column(name="name")
   private String name;

   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "mother_id", nullable=false)
   private Mother mother;

   //constructor, getter, setter
}

MotherController.java

@RestController
@RequestMapping("mothers")
public class MotherController {

   @Autowired
   private MotherService motherService;

   MotherController(MotherService motherService) {
       this.motherService = motherService;
   } 

   @PostMapping
   Mother createMother(@RequestBody Mother mother)  {
       return this.motherService.createMother(mother);
   }
}

MotherService.java

@Service
public class MotherService {

   private MotherRepository motherRepository;

   @Autowired
   public MotherService (MotherRepository motherRepository) {
       super();
       this.motherRepository= motherRepository;
   }

   public Mother createMother(Mother mother)  {

       Kid kid = new Kid("Peter");

       mother.addKid(kid);

       return this.motherRepository.save(mother);
   }
}

到目前为止,母亲和孩子的存储库在没有任何自定义方法的情况下扩展了 JpaRepository。

我的 POST 请求类似于(使用 Postman)

{
   "name":"motherName"
}

现在创建了一个名为 "motherName" 的母亲和一个名为 "Peter" 的孩子。

我的想法:使用 DTO

我现在尝试实现一个包含母亲姓名和孩子姓名的 DTO,将 MotherService 中的此信息映射到实体并通过相应的存储库保存它们,这样我就可以在 POST请求。

motherDto.java

public class mother {
   private String motherName;
   private String kidName;

   //getter, setter

}

所以当我 POST

{
  "motherName":"Susanne",
  "kidName":"Peter"
}

甚至更好

{
   "mother": {
       "name":"Susanne"
   },
   "kid": {
       "name":"Peter"
   }
}

一位名叫苏珊娜的母亲和一位名叫彼得的孩子诞生了。

我的问题是

如何将 DTO 映射到两个实体?

还是我做错了什么?有没有更简单的方法来实现我的目标?

第一个解法:

您不能使用 DTO 并使用 Motherkids 以及 Spring MVC 中的 Jackson 的相同结构发送您的 JSON 正确反序列化给你。

{
 id:2,
 name:'sarah'
 kidList:[{id:546,name:'bob'},{id:478,name:'tom'}]
}

第二种方案:

如果你想在 JSON 和模型中使用不同的结构,你可以使用像 @JsonProperty@JsonDeserialize 这样的 Jackson 注释。阅读 this like 了解更多信息。

第三种解法:

您可以使用 DozzerMapperDTO 和模型之间进行复杂映射。您定义 XML 的文件以将每个模型映射到您的 DTODozzerMapper 将您的 DTO 映射到您的 models.Read this link 以获取更多信息。

你有两种方法:

  1. 自己将DTO映射到实体。在这种情况下,您应该创建自定义映射器并定义 DTO 应如何准确转换为实体。然后在服务中注入并使用您的自定义映射器。
  2. 使用现有映射器库之一。例如,好的候选人是 MapStruct and ModelMapper。您可以在相应的入门指南中找到使用示例。

我知道这是个老问题,可能早就解决了,但让我对这个问题提出不同的看法。

另一种选择是设计一个 DTO,仅用于创建您提到的两个实体。您可以调用此 MotherChildCreationDTO 或类似的名称,这样名称就已经传达了它的用途,并且可以创建一个使用 DTO 的 REST 目标。

非对称 DTO(接收和发送)是一种既定模式,并且 DTO 以任何方式与 REST 控制器紧密耦合。