Home > OS >  how to POST with a foreign key when the other table already exists - using spring
how to POST with a foreign key when the other table already exists - using spring

Time:12-30

So I'm learning Spring Boot for my uni project and I want to add values to a table that has a foreign key when the FK already exists in the other table. Im new to this stuff and I don'g really know what to do with the error that Spring gives me.

My entity

    package com.example.Projekt21.entity;

    import javax.persistence.*;

    @Table
    @Entity
    public class Oscar {

    @Id
    @GeneratedValue
    private Long id;
    private Long rok;
    @OneToOne
    @JoinColumn(name = "idFilmu", referencedColumnName = "id")
    private Film idFilmu;
    @ManyToOne
    @JoinColumn(name = "idRezyserea", referencedColumnName = "id")
    private Rezyser idRezysera;


    public Oscar(Long idOscary, Long rok) {
        this.id = idOscary;
        this.rok = rok;
    }

    public Oscar() {
    }

    public Long getIdOscar() {
        return id;
    }

    public void setIdOscar(Long idOscary) {
        this.id = id;
    }

    public Long getRok() {
        return rok;
    }

    public void setRok(Long rok) {
        this.rok = rok;
    }

    public Film getIdFilmu() {
        return idFilmu;
    }

    public void setIdFilmu(Film idFilmu) {
        this.idFilmu = idFilmu;
    }
}

Controller

package com.example.Projekt21.controller;

import com.example.Projekt21.entity.Oscar;
import com.example.Projekt21.service.OscarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping
public class OscarController {

private final OscarService oscarService;

@Autowired
public OscarController(OscarService oscarService){
    this.oscarService = oscarService;
}

@GetMapping(path = "/oscar/get")
public List<Oscar> getOscar(){
    return oscarService.getOscar();
}

@PostMapping(path = "/oscar/post")
public void registerNewOscar(@RequestBody Oscar oscar){
    oscarService.addNewOscar(oscar);
}

@DeleteMapping(path = "/oscar/delete/{oscarId}")
public void deleteOscar(@PathVariable("oscarId")Long oscarId){
    oscarService.deleteOscar(oscarId);
}

@PutMapping(path = "/oscar/put/{oscarId}")
public void updateStudent(
        @PathVariable("oscarId") Long oscarId,
        @RequestParam(required = false) Long rok) {
    oscarService.updateOscar(oscarId, rok);
}

}

Service

    package com.example.Projekt21.service;

     import com.example.Projekt21.entity.Oscar;
    import com.example.Projekt21.repository.OscarRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    import javax.transaction.Transactional;
    import java.util.List;
    import java.util.Objects;

    @Service
    public class OscarService {

    private final OscarRepository oscarRepository;

    @Autowired
    public OscarService(OscarRepository oscarRepository){
        this.oscarRepository = oscarRepository;
    }

    public List<Oscar> getOscar(){
        return oscarRepository.findAll();
    }

    public void addNewOscar(Oscar oscar){
        oscarRepository.save(oscar);
    }

    public void deleteOscar(Long oscarId){
        boolean exists = oscarRepository.existsById(oscarId);
        if(!exists){
            throw new IllegalStateException("Oscar o numerze id:  "   oscarId   " nie istenieje");
        }
        oscarRepository.deleteById(oscarId);
    }

    @Transactional
    public void updateOscar(Long oscarId, Long rok) {
        Oscar oscar = oscarRepository.findById(oscarId).orElseThrow(() -> new IllegalStateException(
                "Oscar o numerze id:  "   oscarId   " nie istnieje"));

        if (rok != null && rok > 0 && rok != oscar.getRok()) {
            oscar.setRok(rok);
        }
    }
}

My request

{
    "rok": "2020",
    "idFilmu": "1",
    "idRezysera": "2"
}

Error Message

JSON parse error: Cannot construct instance of `com.example.Projekt21.entity.Film` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('1');

Can someone please give me a simple explanation on how to fix my problem? Thanks

EDIT: Film entity

package com.example.Projekt21.entity;

import javax.persistence.*;

@Table
 @Entity
public class Film {

@Id
@GeneratedValue
private Long id;
private String tytul;
private String gatunek;
private Long rok_produkcji;

@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
private Rezyser rezyser;

public Film(String tytul, String gatunek, Long rok_produkcji, Rezyser 
rezyser) {
    this.tytul = tytul;
    this.gatunek = gatunek;
    this.rok_produkcji = rok_produkcji;
    this.rezyser = rezyser;
}

public Film() {
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getTytul() {
    return tytul;
}

public void setTytul(String tytul) {
    this.tytul = tytul;
}

public String getGatunek() {
    return gatunek;
}

public void setGatunek(String gatunek) {
    this.gatunek = gatunek;
}

public Long getRok_produkcji() {
    return rok_produkcji;
}

public void setRok_produkcji(Long rok_produkcji) {
    this.rok_produkcji = rok_produkcji;
}

public Rezyser getRezyser() {
    return rezyser;
}

public void setRezyser(Rezyser rezyser) {
    this.rezyser = rezyser;
}

@Override
public String toString() {
    return "Film{"  
            "id="   id  
            ", tytul='"   tytul   '\''  
            ", gatunek='"   gatunek   '\''  
            ", rok_produkcji="   rok_produkcji  
            ", id_rezysera="   rezyser  
            '}';
}

}

and Rezyser

public class Rezyser {

@Id
@GeneratedValue
private Long id;
private String imie;
private String nazwisko;
private Date data_urodzenia;
private String kraj_pochodzenia;

@OnDelete(action = OnDeleteAction.CASCADE)
@OneToMany(mappedBy = "rezyser")
private List<Film> filmList;

public Rezyser(String imie, String nazwisko, Date data_urodzenia, String 
kraj_pochodzenia) {
    this.imie = imie;
    this.nazwisko = nazwisko;
    this.data_urodzenia = data_urodzenia;
    this.kraj_pochodzenia = kraj_pochodzenia;
}
//getters, setters, toString and creators

}

EDIT 2

sharing my project: https://github.com/TheFandorn/Projekt2.1

CodePudding user response:

Okey, so if anyone in the future has a similar problem this is the solution:

Controller

@PostMapping(path = "/oscar/post/{filmId}")
public Oscar addOscarToFilm(@PathVariable Long filmId, @RequestBody OscarDto 
oscar){
    return oscarService.addOscarToFilm(filmId, oscar);
}

Service

    public Oscar addOscarToFilm(Long filmId, OscarDto oscarDto) {
    if (filmId == null) {
        throw new IllegalArgumentException("Id of Film you want to find is 
null");
    }

    var film = filmRepository.findById(filmId)
            .orElseThrow(() -> new IllegalArgumentException("Cannot find film 
with this id: "   filmId));

    var filmRezyser = film.getRezyser();
    var oscar = oscarDto.toOscar();

    oscar.setFilm(film);
    oscar.setRezyser(filmRezyser);

    return oscarRepository.save(oscar);
}

dto

package com.example.Projekt21.dto;

import com.example.Projekt21.entity.Oscar;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class OscarDto {
Long rok;

public Oscar toOscar() {
    return Oscar
            .builder()
            .rok(rok)
            .build();
}

}

CodePudding user response:

It is great! We can use new class for request body, for example:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AddNewOscarRequest {
    private Long oscarId;
    private Long rok;
    private Long filmId;
    private Long rezyseraId;
}

then:

@PostMapping(path = "/oscar/create")
public Oscar addOscarToFilm(@RequestBody AddNewOscarRequest request){
    return oscarService.addOscarToFilm(request);
}

If you not found entity application throws EntityNotFoundException

filmRepository.findById(filmId)

For mapping you can use new class like "OscarMapper"

  • Related