Chris
Chris

Reputation: 5653

How to map a DTO to multiple entities?

I'm writing a Spring Application, which has two entities that are related by a one to many relationship, lets call them mother and kid.

When I create a mother entity via POST request, I want a kid entity be created automatically. Using the @OneToMany and @ManyToOne annotations, that works fine. At least, as long as I provide the kid information within the MotherService.

Here is my code

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);
   }
}

The repositories for mother and kid extend the JpaRepository without any custom methods so far.

My POST request is something like (using Postman)

{
   "name":"motherName"
}

Now a mother is created with a name "motherName" and a kid with the name of "Peter".

My idea: Using a DTO

I now try to implement a DTO, that contains the mothers name and the kids name, map this information in the MotherService to the entities and save them via the corresponding repository, so I can define both names in the POST request.

motherDto.java

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

   //getter, setter

}

So when I POST

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

or even better

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

a mother with name Susanne and a kid with name Peter are created.

My question is

How do I map a DTO to two entities?

Or do I not get something right? Is there an easier way to achieve my goal?

Upvotes: 0

Views: 15524

Answers (3)

Aarkon
Aarkon

Reputation: 488

I know this is old and probably long solved, but let me offer a different take on the subject.

Another option would be to design a DTO solely for the purpose of creating the two entities you mentioned. You could call this MotherChildCreationDTO or something like that so the name already conveys its use and maybe create a REST-target consuming the DTO.

Asymmetric DTOs (receiving and sending) are an established pattern, and the DTOs are closely coupled to the REST controller any way.

Upvotes: 4

Oleksii Zghurskyi
Oleksii Zghurskyi

Reputation: 4365

You have 2 ways:

  1. Map DTO to entities by yourself. In this case, you should create custom mapper and define how exactly DTO should be converted to entity. Then just inject and use your custom mapper in service.
  2. Use one of existing mapper libraries. For example, good candidates are MapStruct and ModelMapper. You can find usage examples in corresponding getting started guides.

Upvotes: 2

Javad Kargar
Javad Kargar

Reputation: 1425

First solution:

You can don't use DTO and send your JSON with same structure of Mother and kids and Jackson in Spring MVC deserialize it correctly for you.

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

Second solution:

If you want to different structure in JSON and Models and you can use Jackson annotation like @JsonProperty or @JsonDeserialize. Read this like for more information.

Third solution:

You can use DozzerMapper for complex mapping between your DTO and your Model. you define XML's file for mapping each model to your DTO and DozzerMapper map your DTO to your models.Read this link for more information.

Upvotes: 2

Related Questions