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

时间:2019-02-01 17:03:33

标签: java spring spring-mvc spring-data-jpa dto

我正在写一个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请求类似于(使用邮递员)

{
   "name":"motherName"
}

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

我的想法:使用DTO

我现在尝试实现一个DTO,其中包含母亲的名字和孩子的名字,将此信息在MotherService中映射到实体,并通过相应的存储库保存它们,因此我可以在POST请求中定义这两个名字。 / p>

motherDto.java

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

   //getter, setter

}

所以当我发布

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

甚至更好

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

创建了一个名字叫Susanne的母亲和一个名字叫Peter的孩子。

我的问题是

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

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

3 个答案:

答案 0 :(得分:1)

第一个解决方案:

您不能使用DTO并以JSONMother中的kidsJacksonSpring MVC相同的结构来发送{ id:2, name:'sarah' kidList:[{id:546,name:'bob'},{id:478,name:'tom'}] }

JSON

第二个解决方案:

如果您想在@JsonProperty和模型中使用不同的结构,则可以使用@JsonDeserializeDozzerMapper之类的Jackson注释。阅读this like了解更多信息。

第三种解决方案:

您可以使用DTODTO和模型之间进行复杂的映射。您可以定义XML文件,以将每个模型映射到您的DozzerMapperDTO将您的class Statement { public: Statement(); ~Statement(); void BindInt(int index, int value); void BindInt(std::string name, int value); void BindInt64(int index, int value); void BindInt64(std::string name, int value); void BindText(int index, std::string value); void BindText(std::string name, std::string value); }; Statement::Statement(){} Statement::~Statement(){} void Statement::BindInt(int index, int value){} void Statement::BindInt(std::string name, int value){} void Statement::BindInt64(int index, int value){} void Statement::BindInt64(std::string name, int value){} void Statement::BindText(int index, std::string value){} void Statement::BindText(std::string name, std::string value){} 映射到您的模型。有关详细信息,请阅读this link

答案 1 :(得分:1)

您有2种方法:

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

答案 2 :(得分:1)

我知道这很久了,也许已经解决了,但是让我对这个问题提出不同的看法。

另一个选择是仅设计DTO来创建您提到的两个实体。您可以将其称为MotherChildCreationDTO或类似名称,以便该名称已经传达了其用法,并可能创建一个使用DTO的REST目标。

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