2

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.

notSoEasy
  • 21
  • 2

1 Answers1

0

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;
M A
  • 71,713
  • 13
  • 134
  • 174
  • Thanks for your response I just want to remove relationship from parent to child so i put null in clientParent. What i want to achieve is to remove relationship between child and parent by setting null to the parent property not only changing the id of entity. Maybe this is not the way to do it ? – notSoEasy Feb 22 '21 at 21:57
  • @notSoEasy I don't think setting `clientParent` to null is the problem. The problem seems because you are setting the `id` property (not `clientParent`) of the child to null. – M A Feb 23 '21 at 09:23
  • I have launched debug to verify and my Id on the child client is not null, the clientParent is null, for example this is the client to be save that cause error client = {Client@10395} name = "non équipe de lui en fait" address = {Address@10399} headOffice = false clientParent = null id = "e17ee791-1de3-4d8e-8fa5-2f9303815506" createdDate = {Timestamp@10401} "2021-02-22 17:35:35.02" modifiedDate = {Timestamp@10402} "2021-02-22 17:36:25.057" – notSoEasy Feb 23 '21 at 15:24