Facing exception HibernateException: identifier of an instance of <Class> was altered from <old> to <new> spring

Viewed 547

I'm using spring with lombok and mapstruct and postgresSQL.

I'm facing an error on a udirectional @ManyToOne relationship on Parent / Child relationship, with my class Client

Here is my Client class :

@Getter
@Setter
@Table(name = "client")
public class Client extends AbstractEntity {

    private String name;

    @ManyToOne(cascade = CascadeType.ALL)
    private Address address;

    private boolean headOffice;

    @ManyToOne(cascade= CascadeType.ALL)
    @JoinColumn(name="client_parent_id")
    public Client clientParent;
}

Here is my abstractEntity to generate Id and some data:

@MappedSuperclass
@Getter
@Setter
@RequiredArgsConstructor
public class AbstractEntity {

    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
            name = "UUID",
            strategy = "org.hibernate.id.UUIDGenerator"
    )
    private String id;

    @CreationTimestamp
    private Timestamp createdDate;

    @UpdateTimestamp
    private Timestamp modifiedDate;
}

Here is my client Service :

@Service
public class ClientService {

    private final ClientRepository clientRepository;
    private final ClientMapper clientMapper;

    ClientService(ClientRepository clientRepository, ClientMapper clientMapper) {
        this.clientRepository = clientRepository;
        this.clientMapper = clientMapper;
    }

    Client getClient(String id) throws FunctionalException {
        return this.clientRepository.getById(id)
                .orElseThrow(
                        () -> new FunctionalException("Client not found")
                );
    }

    public ClientDto createOrUpdateClient(ClientDto clientDto, String id) throws FunctionalException {

        Client client;
        if (id == null) {
            verifyInExistence(clientDto);
            client = this.clientMapper.toEntity(clientDto);
        } else {
            client = this.getClient(id);
            this.clientMapper.updateClientFromDto(clientDto, client);
        }
        verifyParent(client, clientDto.getClientParentId());

        return this.clientMapper.toDto(this.clientRepository.save(client));
    }

    private void verifyParent(Client client, String parentId) {
        if (parentId != null) {
            client.setClientParent(this.getClient(parentId));
        } else {
            client.setClientParent(null);
        }
    }

    private void verifyInExistence(ClientDto clientDto) throws FunctionalException {
        clientRepository.findByName(clientDto.getName()).ifPresent(s -> {
            throw new FunctionalException(String.format("Client '%s' already exist", clientDto.getName()));
        });
    }
}

And my Rest Controller :

@RestController
@RequestMapping(path = "/api/client")
public class ClientResource {

    private final ClientService clientService;

    ClientResource(ClientService clientService) {
        this.clientService = clientService;
    }

    @PostMapping
    ClientDto addClient(@RequestBody ClientDto clientDto) throws FunctionalException {
        return this.clientService.createOrUpdateClient(clientDto, null);
    }

    @PutMapping(path = "/{id}")
    ClientDto updateClient(@PathVariable String id, @RequestBody ClientDto clientDto) throws FunctionalException {
        return this.clientService.createOrUpdateClient(clientDto, id);
    }
}

When i'm posting a new client with a parent or without a parent it's okay, all goes right.

But when I try to update (by using put in clientResource) in order to remove relationship between a child and parent entity I have an Hibernate Exception like this :

HibernateException: identifier of an instance of xxxx.model.Client was altered from 7fa60bf2-e176-4b96-aae4-cbfa6461cb0e to null

I read a lot of post but i'm not in the case my Id are well generated i just don't understand why i can't set null to parent to define a chil without parent. I tried also to add childrens as OneToMany but didn't understand the need to do this.

Thanks a lot for all your reponse ! :) And sorry for the bad english.

1 Answers

The error message indicates that the id value of the entity Client is being changed to null. This is most likely happening in this line:

this.clientMapper.updateClientFromDto(clientDto, client);

When doing an update on an existing object, you should not change its id (see this). Either you need to make sure the clientDto does not have a null id value, or you need to exclude setting the id of client from the clientDto.

Another note: if you're using generated identifier values (@GeneratedValue(generator = "UUID")) then it may be a good idea to remove the setter on the id field, because the value will be generated automatically:

@Setter(AccessLevel.NONE)
private String id;
Related