2
respostas

Foreign Key em um método post

Oi, estou começando java e spring, e estou desenvolvendo um pequeno projetinho pessoal apenas para praticar um pouco mais, entrentando estou com um problema e não encontrei a solução ainda. Em resumo eu tenho duas tabelas no meu banco "Places" e "Categories", com uma relação muitos para um (Uma categoria pode ter varios lugares, mas um lugar só pode ser de uma categoria). O problema ocorre quando tento cadastrar um place e surge um erro que acredito ser em relação a FK (pois todas as outras tabelas que não tem FK eu consegui cadastrar sem problemas).

Segue minhas entities:

@Entity(name = "categories") @Table(name = "categories") @EqualsAndHashCode (of = "id") @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class Category {

@Id
@GeneratedValue (strategy = GenerationType.UUID)
private String id;

private String name;

public Category(RequestCategoriesDTO requestCategoriesDTO) {
    this.name = requestCategoriesDTO.name();
}

}

@Entity(name = "places") @Table(name = "places") @EqualsAndHashCode(of = "id") @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class Place {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String id;

private String name;

private String address;

@ManyToOne
@JoinColumn(name = "categories_id", referencedColumnName = "id")
private Category categories_id;

private Integer value_in_cents;

public Place(RequestPlacesDTO requestPlacesDTO) {
    this.name = requestPlacesDTO.name();
    this.address = requestPlacesDTO.address();
    this.categories_id = requestPlacesDTO.categories_id();
    this.value_in_cents = requestPlacesDTO.value_in_cents();
}

}

Segue meu PlacesController:

@RestController @RequestMapping("/places") public class PlacesController {

@Autowired
private PlaceRepository repository;

@GetMapping
public ResponseEntity getAllPlaces() {
    var allPlaces = repository.findAll();

    return ResponseEntity.ok(allPlaces);
}

@PostMapping("/register")
public ResponseEntity registerPlaces(@RequestBody @Valid RequestPlacesDTO data){
    Place newPlace = new Place(data);
    repository.save(newPlace);

    return ResponseEntity.ok().buil();
}

}

Segue JSON da requisição: { "name": "Loca Madre", "address": "Av. ", "categories_id": "b3e08a43-2220-479b-8b81-a950a145a9e7", "value_in_cents": 7000 }

E segue o erro que aparece no terminal: 2023-07-21T19:37:12.898-03:00 WARN 11904 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of br.com.spring.spring.domain.Category (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('b3e08a43-2220-479b-8b81-a950a145a9e7')]

2 respostas

Kaiana, bom dia.

Eu estou olhando seu codigo, e no meu ponto de vista consigo identificar diversos fatores.

O primeiro e que as suas classes você não implementou o Serializable

Segundo e que como uma categoria pode conter varios lugares, logo você na sua classe de categoria você precisava instanciar uma lista de lugares ou seja ficaria assim

@Entity(name = "categories") @Table(name = "categories") @EqualsAndHashCode (of = "id") @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class Category {
@Id
@GeneratedValue (strategy = GenerationType.UUID)
private String id;

private String name;

@JsonIgnore
@OneToMany(mappedBy = "categories_id")
private List<Place> places = new ArrayList<>();

public Category(RequestCategoriesDTO requestCategoriesDTO) {
    this.name = requestCategoriesDTO.name();
}
}

E na classe de Places ficaria dessa maneira


@Entity(name = "places") @Table(name = "places") @EqualsAndHashCode(of = "id") @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class Place {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String id;

private String name;

private String address;

@ManyToOne
@JoinColumn(name = "places_id")
private Category categories_id;

private Integer value_in_cents;

public Place(RequestPlacesDTO requestPlacesDTO) {
    this.name = requestPlacesDTO.name();
    this.address = requestPlacesDTO.address();
    this.categories_id = requestPlacesDTO.categories_id();
    this.value_in_cents = requestPlacesDTO.value_in_cents();
}
}

Creio que isso resolvera o seu problema, eu implemento desse jeito e normalmente da certo.

Como voce esta usando java, deveria usar o padrão da linguagem para nome de variaveis, que é camel case, ao inves do snake case que voce utilizou. Eu nao vi como voce fez seu DTO, mas se voce usou objeto, voce precisa passar no json como objeto, e voce esta usando atributo.

"categories_id": "b3e08a43-2220-479b-8b81-a950a145a9e7"

se voce usou no dto um objeto o correto seria assim:

"categories_id": { "id": "b3e08a43-2220-479b-8b81-a950a145a9e7" }

outro detalhe nao precisa colocar esse id no nome da variavel e se nao for uma lista, nao precisa colocar no plural. Isso pode ser besteira, mas é importante para voce nao se confundir.

Quando alguem ve categories vai associar a uma lista de categorias, e no seu caso é apenas uma.

Nao precisa deixa o nome das suas variaveis igual ao banco. O jpa ja converte o padrao camel case para snake case no banco de dados.

Se no seu DTO voce usa o categories como atributo, ai voce vai precisar fazer a conversao manual ou usar a biblioteca modelmapper para fazer a transformacao do dto do json para o model object.