6
respostas

Save em objeto que usa herança

Boa tarde, Tenho um objeto pessoa, que é pai de varias classes, como funcionário, cliente e fornecedor. Quando crio um funcionario e esse mesmo não existe com o nome em pessoa, o insert é feito normal, só que se ja existir uma pessoa com esse mesmo nome ligada a outra entidade, o hibernate tenta fazer um insert na tabela pessoa, em vez, de fazer apenas o update dos campos de pessoa e insert nos campos da entidade que estou cadastrando. Não sei o que estou fazendo de errado, alguém pode me dar um exemplo dessa implementação?

Classe pessoa

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "person")
@Inheritance(strategy= InheritanceType.JOINED)
public class Person extends Model{

    @NotNull
    private String name;

    @NotNull
    @Column(unique = true)
    private String docIdentification;

    private String phone;

    private String email;

    private String contactName;

}

Classe fornecedor

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "supplier")
@Entity
public class Supplier extends Person {
    @NotNull
    private LocalDateTime createdAt;

    @NotNull
    private LocalDateTime updatedAt;

    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "location_id", referencedColumnName = "id")
    private Location location;

    private String website;

    private String observation;
}

Metodo service onde é feito o save

List<Person> byNameIgnoreCase = personRepository.findByNameIgnoreCase(supplierForm.getName());
        Supplier supplier = new Supplier();
        if(!byNameIgnoreCase.isEmpty()){
            supplier.setId(byNameIgnoreCase.get(0).getId());
        }

        //person
        supplier.setName(supplierForm.getName());
        supplier.setPhone(supplierForm.getPhone());
        supplier.setEmail(supplierForm.getEmail());
        supplier.setContactName(supplierForm.getContactName());
        supplier.setDocIdentification(supplierForm.getDocIdentification());

        //Supplier
        supplier.setCreatedAt(LocalDateTime.now());
        supplier.setUpdatedAt(LocalDateTime.now());
        supplier.setLocation(location);
        supplier.setWebsite(supplierForm.getWebsite());
        supplier.setObservation(supplierForm.getObservation());

        return new SupplierDTO(repository.save(supplier));
6 respostas

Oi Pedro!

O problema é que você está instanciando um novo objeto e com isso a JPA considera que ele está no estado TRANSIENT e não MANAGED.

Seu código deveria estar assim:

if(!byNameIgnoreCase.isEmpty()) {
    supplier = personRepository.getReferenceById(byNameIgnoreCase.get(0).getId());
}

Se o método esiver anotado com @Transactional, a JPA vai fazer o update automático.

Esse método getReferenceById funcionaria como? Ele está no repository de pessoa e retorna um supplier? Poderia me dar um exempo? Não consegui localizar esse metodo no meu repository. Código do PersonRepository:

public interface PersonRepository extends JpaRepository<Person, UUID> {
    List<Person> findByNameIgnoreCase(String name);
}

Esse método é para buscar um objeto pela chave primária no banco de dados e vem da herança da interface JpaRepository do Spring Data. Foi utilizado ao longo do curso nas funcionalidades de atualizar, remover e detalhar.

Eu vi de novo a aula de detalhes e não vi onde usou.

e esse metodo não existe na minha classe que extend o JpaRepository

Oi Pedro!

Esse print que você mandou é do curso antigo.

No novo curso o getReferenceById é mostrado nesse vídeo, lá pelo minuto 03:00: https://cursos.alura.com.br/course/spring-boot-3-desenvolva-api-rest-java/task/115969

O problema é o seguinte: Minha tabela "person" ja tem o nome desse "supplier" cadastrado... so que está vinculada a um cliente por exemplo... Quando eu faço esse metodo getReferenceById ele está trazendo nulo, porque não existe ainda na tabela "supplier", eu preciso que se tiver com esse nome na tabela "person" que faça um update nela e um insert na "supplier".

Desculpe talvez não estou conseguindo me expressar