0

I have a model class which is used in post(create) and put(update) rest API

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@Entity(name= "employee")
public class employeeDetail {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long employeeId;
    @NonNull
    private String employeeName;

}

So since employee id to be nullable on add, while it has to be passed when update operation. What is the best to implement?

Note: In this case employee id is a primary key, the same situation is possible for non-primary key fields as well. I use Spring boot, Spring data JPA and hibernate. Database is mariadb.

Sam
  • 1,298
  • 6
  • 30
  • 65

2 Answers2

0

Something like this:

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.transaction.Transactional;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Optional;


@Getter
@Setter
@NoArgsConstructor
@Entity(name = "employee")
class EmployeeDetail {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long employeeId; //Long is better!

    @NotNull
    private String employeeName;


    //    Needed just for conversion -> use some mapper, and remove this constructor
    public EmployeeDetail(EmployeeDetailDTO employeeDetailDTO) {
        this.employeeId = employeeDetailDTO.getEmployeeId();
        this.employeeName = employeeDetailDTO.getEmployeeName();
    }
}

interface EmployeeDetailRepo extends JpaRepository<EmployeeDetail, Long> {
}

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
class EmployeeDetailDTO {

    private Long employeeId;

    @NotNull
    private String employeeName;

//    Other fields

    //    Needed just for conversion -> use some mapper, and remove this constructor
    public EmployeeDetailDTO(EmployeeDetail employeeDetail) {
        this.employeeId = employeeDetail.getEmployeeId();
        this.employeeName = employeeDetail.getEmployeeName();
    }
}

@Service
class EmpDetailService {

    private EmployeeDetailRepo employeeDetailRepo;

    @Autowired
    public EmpDetailService(EmployeeDetailRepo employeeDetailRepo) {
        this.employeeDetailRepo = employeeDetailRepo;
    }

    public EmployeeDetailDTO add(EmployeeDetailDTO employeeDetailDTO) {
//        map EmployeeDetailDTO to EmployeeDetail
        EmployeeDetail employeeDetail = new EmployeeDetail(employeeDetailDTO);
        EmployeeDetail employeeDetail1FromDB = employeeDetailRepo.save(employeeDetail);
//        map back to dto
        return new EmployeeDetailDTO(employeeDetail1FromDB);
    }

    @Transactional
    public EmployeeDetailDTO edit(Long id, EmployeeDetailDTO employeeDetailDTO) {
//        map EmployeeDetailDTO to EmployeeDetail
        Optional<EmployeeDetail> byId = employeeDetailRepo.findById(id);
        EmployeeDetail employeeDetailFromDB = byId.orElseThrow(() -> new RuntimeException("No such user with id: " + id));
        employeeDetailFromDB.setEmployeeName(employeeDetailDTO.getEmployeeName());
        return new EmployeeDetailDTO(employeeDetailFromDB);
    }
}

@RequestMapping
class Controller {
    private EmpDetailService empDetailService;

    @Autowired
    Controller(EmpDetailService empDetailService) {
        this.empDetailService = empDetailService;
    }

    @PostMapping("/add")
    public ResponseEntity<EmployeeDetailDTO> add(@Valid @RequestBody EmployeeDetailDTO employeeDetailDTO) {
        EmployeeDetailDTO added = empDetailService.add(employeeDetailDTO);
        return new ResponseEntity<>(added, HttpStatus.OK);
    }

    @PostMapping("/edit/{id}")
    public ResponseEntity<EmployeeDetailDTO> edit(@PathVariable Long id,
                                                  @Valid @RequestBody EmployeeDetailDTO employeeDetailDTO) {
        EmployeeDetailDTO edited= empDetailService.edit(id, employeeDetailDTO);
        return new ResponseEntity<>(edited, HttpStatus.OK);
    }
}
-1

Since you expect Hibernate to generate yuor id on insert it should be nullable, so its type.

Just change employeeId to Integer.


From a design point of view, consider to create 2 different business domain classes, one for insert with no id and one for update/select with non nullable id.

public class EmployeeRegistration {
    @NonNull
    private String name;
}

public class EmployeeDetail {
    @NonNull
    private Integer employeeId;
    @NonNull
    private String name;
}

Then provade methods to transform them to database entities.

noiaverbale
  • 1,550
  • 13
  • 27