Home > Blockchain >  My repository is not called in my service - Spring Data JPA
My repository is not called in my service - Spring Data JPA

Time:07-23

I don't understand why my weight record Repository is not called in spite of my code. I have written some logs before and after the weight record repository call. In my console, I can see that logs are called before and after, but not my repository. I have a code 200 OK, but in my database, my data is always here. I don't understand why. My Tomcat port is set to port 7777. I can create and read data but not delete it.

Just below my code : ENTITY, CONTROLLER, REPOSITORY and SERVICE.

My request in Insomnia

Result of request in console:
Result of request in console

CodePudding user response:

The reason

The reason of the issue is this part of the code

personConnected.getWeightsList().contains(weightRecordToDelete)

Why it happens?

There is a spring data property spring.jpa.open-in-view and it is true by default. It means that JPA Persistent Context (Hibernate Session) is opened during entire HTTP request. What is this spring.jpa.open-in-view=true property in Spring Boot?

If Persistent Context is opened, fetch = FetchType.LAZY property in the code below doesn't work at all.

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person")
private List<WeightRecord> weightsList = new ArrayList<WeightRecord>();

When you do personConnected.getWeightsList().conatins(), Hibernate loads weightsList in the background. That's why the last SQL log entry is logged.

    select
        weightslis0_.person_id_person as person_i8_3_0_
    ...
    from
        weight_record weightslis0_ 
    where
        weightslis0_.person_id_person=?

So when you delete a WeightRecord, it remains in the Person.weightsList, because of it was loaded by personConnected.getWeightsList().conatins().

When HTTP request is completed, Persistent Context becomes closed, and Hibernate flushes all changes to the database. There is cascade = CascadeType.ALL on the Person side, so Hibernate should keep in mind a deleted WeightRecord in the weightsList. So it does nothing, because you could delete WeightRecord and insert it by some reasons again.

You can verify statements above just by removing personConnected.getWeightsList().conatins() part of the code, delete will start work.

How to solve

  1. Set spring.jpa.open-in-view=false in the application.property. So you will have LazyInitializationException with personConnected.getWeightsList().conatins()

  2. Remove personConnected.getWeightsList().conatins() code. You can do the same just comparing WeightRecord.Person.id and a current Person.id.

        Optional<Person> personConnected = personRepository.findById(appUserConnectedId);
        if (personConnected.isPresent()  ) {
            WeightRecord weightRecordToDelete = weightRecordRepository.findById(weightId).orElseThrow();
            Long userPersonId = personConnected.get().getIdPerson();
            Long recordPersonId = weightRecordToDelete.getPerson().getIdPerson();
            if (Objects.equals(userPersonId, recordPersonId)) {
                logger.info("SERVICE FOR DELETING");
                return ResponseEntity.ok(weightRecordServiceImpl.deleteWeightById(weightRecordToDelete));
            }
        }

        logger.info("BAD USER FOR BAD WEIGHT");
        return ResponseEntity.notFound().build();

Now you can keep cascade = CascadeType.ALL on the weightsList on Person side.

Notes

Always use spring.jpa.open-in-view=false. LazyInitializationException is your friend.

Always use fetch = FetchType.LAZY on the @ManyToOne part of the association. It is FetchType.EAGER by default.

    @ManyToOne(fetch = FetchType.LAZY)
    private Person person;

Never use Jackson annotations like @JsonIgnore and Hibernate Validator annotations like @Min(1) with entities. Use PersonEntity class for an entity and Person for JSON. Do mapping on the service level.

CodePudding user response:

In fact, i have juste deleted the CascadeType.ALL from my @OneToMany entity Person and all is working. I can create, read and delete records from database.
But I'am going to investigate more this problem to understand in a better way its origin.

    @Entity
    @Table(name = "person")
    public class Person implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_person")
    private Long idPerson;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "id_initial_data")
    private InitialData userInitData;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "id_user")
    private AppUser appUserPerson;
    
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "person")
    private List<WeightRecord> weightsList = new ArrayList<WeightRecord>();
  • Related