Home > database >  OneToMany relationship not saving correctly into Postgresql
OneToMany relationship not saving correctly into Postgresql

Time:01-06

Thanks a lot for taking time to read my post.

Please could you help me.

I want to have a oneToMany relationship in my database such as: RelationShip Between Objects in DB

I am using Spring, JPA, Mappers and Repos to work with these values. Eveything saves correctly and is working.

Only thing is the save in the database of a "CaserneJpa" when it contains "PompierJpa" and "CamionJpa" entities it doesn't save the caserne_id into the pompier line in the pompiers table.

I know my repos are working properly (saving into DB works) so I assume it's coming from the OneToMany relationship.

My JPA Objects:

@Getter
@Setter
@Entity
@Table(name = "casernes")
public class CaserneJpa {

    @Id
    @Nonnull
    private Integer id;
    
    @Embedded
    private CoordonneeJpa coordonnee;
    
    @OneToMany(mappedBy="caserne", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<CamionJpa> camions;

    @OneToMany(mappedBy="caserne", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<PompierJpa> pompiers;
}


@Getter
@Setter
@Entity
@Table(name = "interventions")
public class InterventionJpa {
    
    @Id
    @Nonnull
    private UUID id;
    
    private Integer idCapteur;
    
    private Date date;
    
    private CoordonneeJpa coordonnee;
    
    @OneToMany(mappedBy="intervention", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<CamionJpa> camions;

    @OneToMany(mappedBy="intervention", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<PompierJpa> pompiers;

}


@Getter
@Setter
@Entity
@Table(name = "camions")
public class CamionJpa {
    
    @Id
    @Nonnull
    private Integer id;
    
    private Integer places;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "caserne_id")
    private CaserneJpa caserne;
    
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "intervention_id")
    private InterventionJpa intervention;

}


@Getter
@Setter
@Entity
@Table(name = "pompiers")
public class PompierJpa {
    
    @Id
    @Nonnull
    private Integer id;

    private String prenom;
    
    private String nom;
    
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "caserne_id")
    private CaserneJpa caserne;
    
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "intervention_id")
    private InterventionJpa intervention;
    
}

TestCode So I created a test code that creates a caserne object with pompiers and camions to see if it manages to generate properly, it did indeed create the tables and added the values into all the tables but with missing information

public void create() {
        
        Pompier pompier = new Pompier();
        Pompier pompier2 = new Pompier();
        Camion camion = new Camion();
        Camion camion2 = new Camion();
        
        pompier.setId(1);
        pompier.setNom("Gauchoux");
        pompier.setPrenom("Xav");
        
        pompier2.setId(2);
        pompier2.setNom("Biosca");
        pompier2.setPrenom("Coco");
        
        camion.setId(1);
        camion.setPlaces(2);
        
        camion2.setId(2);
        camion2.setPlaces(1);
        
        ArrayList<Pompier> listPompier = new ArrayList<>();
        listPompier.add(pompier);
        listPompier.add(pompier2);
        
        ArrayList<Camion> listCamion = new ArrayList<>();
        listCamion.add(camion);
        listCamion.add(camion2);
        
        Coordonnee c = new Coordonnee();
        c.setLatitude("1");
        c.setLongitude("1");
        
        Caserne caserne = new Caserne();
        
        caserne.setId(1);
        caserne.setCamions(listCamion);
        caserne.setPompiers(listPompier);
        caserne.setCoordonnee(c);
        
        caserneRepository.save(caserneMapper.toCaserneJpa(caserne));
        
    }

When I use it, it all goes whell I don't get any errors, and the tables are created properly as I said. We can see the caserne_id integer and intervention_id in the creation of the tables.


Hibernate: 
    
    create table camions (
       id integer not null,
        places integer,
        caserne_id integer,
        intervention_id uuid,
        primary key (id)
    )
Hibernate: 
    
    create table casernes (
       id integer not null,
        latitude varchar(255),
        longitude varchar(255),
        primary key (id)
    )
Hibernate: 
    
    create table interventions (
       id uuid not null,
        latitude varchar(255),
        longitude varchar(255),
        date timestamp(6),
        id_capteur integer,
        primary key (id)
    )
Hibernate: 
    
    create table pompiers (
       id integer not null,
        nom varchar(255),
        prenom varchar(255),
        caserne_id integer,
        intervention_id uuid,
        primary key (id)
    )
Hibernate: 
    
    alter table if exists camions 
       add constraint FKom9w5spol5vd1ix3oxfde4on0 
       foreign key (caserne_id) 
       references casernes
Hibernate: 
    
    alter table if exists camions 
       add constraint FKantgpwa0an7ktlsewuvjlbpnu 
       foreign key (intervention_id) 
       references interventions
Hibernate: 
    
    alter table if exists pompiers 
       add constraint FKjeg8ji8qlukn6gnrfs5p26tlu 
       foreign key (caserne_id) 
       references casernes
Hibernate: 
    
    alter table if exists pompiers 
       add constraint FK60xhoettofkdthm00wdt9rvmp 
       foreign key (intervention_id) 
       references interventions

...

Started EmergencymanagerApplication in 3.87 seconds (process running for 4.473)
Hibernate: 
    select
        c1_0.id,
        c2_0.caserne_id,
        c2_0.id,
        i1_0.id,
        i1_0.latitude,
        i1_0.longitude,
        i1_0.date,
        i1_0.id_capteur,
        c2_0.places,
        c1_0.latitude,
        c1_0.longitude 
    from
        casernes c1_0 
    left join
        camions c2_0 
            on c1_0.id=c2_0.caserne_id 
    left join
        interventions i1_0 
            on i1_0.id=c2_0.intervention_id 
    where
        c1_0.id=?
Hibernate: 
    select
        c1_0.id,
        c2_0.id,
        c2_0.latitude,
        c2_0.longitude,
        p1_0.caserne_id,
        p1_0.id,
        i1_0.id,
        i1_0.latitude,
        i1_0.longitude,
        i1_0.date,
        i1_0.id_capteur,
        p1_0.nom,
        p1_0.prenom,
        i2_0.id,
        i2_0.latitude,
        i2_0.longitude,
        i2_0.date,
        i2_0.id_capteur,
        c1_0.places 
    from
        camions c1_0 
    left join
        casernes c2_0 
            on c2_0.id=c1_0.caserne_id 
    left join
        pompiers p1_0 
            on c2_0.id=p1_0.caserne_id 
    left join
        interventions i1_0 
            on i1_0.id=p1_0.intervention_id 
    left join
        interventions i2_0 
            on i2_0.id=c1_0.intervention_id 
    where
        c1_0.id=?
Hibernate: 
    select
        c1_0.id,
        c2_0.id,
        c2_0.latitude,
        c2_0.longitude,
        p1_0.caserne_id,
        p1_0.id,
        i1_0.id,
        i1_0.latitude,
        i1_0.longitude,
        i1_0.date,
        i1_0.id_capteur,
        p1_0.nom,
        p1_0.prenom,
        i2_0.id,
        i2_0.latitude,
        i2_0.longitude,
        i2_0.date,
        i2_0.id_capteur,
        c1_0.places 
    from
        camions c1_0 
    left join
        casernes c2_0 
            on c2_0.id=c1_0.caserne_id 
    left join
        pompiers p1_0 
            on c2_0.id=p1_0.caserne_id 
    left join
        interventions i1_0 
            on i1_0.id=p1_0.intervention_id 
    left join
        interventions i2_0 
            on i2_0.id=c1_0.intervention_id 
    where
        c1_0.id=?
Hibernate: 
    select
        p1_0.id,
        c1_0.id,
        c2_0.caserne_id,
        c2_0.id,
        i1_0.id,
        i1_0.latitude,
        i1_0.longitude,
        i1_0.date,
        i1_0.id_capteur,
        c2_0.places,
        c1_0.latitude,
        c1_0.longitude,
        i2_0.id,
        i2_0.latitude,
        i2_0.longitude,
        i2_0.date,
        i2_0.id_capteur,
        p1_0.nom,
        p1_0.prenom 
    from
        pompiers p1_0 
    left join
        casernes c1_0 
            on c1_0.id=p1_0.caserne_id 
    left join
        camions c2_0 
            on c1_0.id=c2_0.caserne_id 
    left join
        interventions i1_0 
            on i1_0.id=c2_0.intervention_id 
    left join
        interventions i2_0 
            on i2_0.id=p1_0.intervention_id 
    where
        p1_0.id=?
Hibernate: 
    select
        p1_0.id,
        c1_0.id,
        c2_0.caserne_id,
        c2_0.id,
        i1_0.id,
        i1_0.latitude,
        i1_0.longitude,
        i1_0.date,
        i1_0.id_capteur,
        c2_0.places,
        c1_0.latitude,
        c1_0.longitude,
        i2_0.id,
        i2_0.latitude,
        i2_0.longitude,
        i2_0.date,
        i2_0.id_capteur,
        p1_0.nom,
        p1_0.prenom 
    from
        pompiers p1_0 
    left join
        casernes c1_0 
            on c1_0.id=p1_0.caserne_id 
    left join
        camions c2_0 
            on c1_0.id=c2_0.caserne_id 
    left join
        interventions i1_0 
            on i1_0.id=c2_0.intervention_id 
    left join
        interventions i2_0 
            on i2_0.id=p1_0.intervention_id 
    where
        p1_0.id=?
Hibernate: 
    insert 
    into
        casernes
        (latitude, longitude, id) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        camions
        (caserne_id, intervention_id, places, id) 
    values
        (?, ?, ?, ?)
Hibernate: 
    insert 
    into
        camions
        (caserne_id, intervention_id, places, id) 
    values
        (?, ?, ?, ?)
Hibernate: 
    insert 
    into
        pompiers
        (caserne_id, intervention_id, nom, prenom, id) 
    values
        (?, ?, ?, ?, ?)
Hibernate: 
    insert 
    into
        pompiers
        (caserne_id, intervention_id, nom, prenom, id) 
    values
        (?, ?, ?, ?, ?)

Result

This is my camions table in Postgresql Camion Table We can see that it was generated and filled properly, except for the caserne_id. When the object was created there was a link, so I don't get why it is lost.

What I tried

I tried playing around with the oneToMany and manyToOne by changing the cascade and other things but nothing seems to be working.

Thanks again for your help.

CodePudding user response:

Bidirectional association should be updated on both sides:

Whenever a bidirectional association is formed, the application developer must make sure both sides are in-sync at all times.

The easiest way to do this is to add some helper methods .addCamion(CamionJpa camion) and .addPompier(PompierJpa pompier):

public class CaserneJpa {
   ...

    @OneToMany(mappedBy="caserne", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<CamionJpa> camions = new ArrayList();
   
   
    @OneToMany(mappedBy="caserne", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<PompierJpa> pompiers = new ArrayList();

   ...

   public void addCamion(CamionJpa camion) {
      this.camions.add(camion);
      camion.setCaserne(this);
   }

   public void addPompier(PompierJpa Pompier) {
      this.pompiers.add(pompier);
      pompier.setCaserne(this);
   }
}

Then you can change the code to:

public void create() {
        
        Pompier pompier = new Pompier();
        Pompier pompier2 = new Pompier();
        Camion camion = new Camion();
        Camion camion2 = new Camion();
        
        pompier.setId(1);
        pompier.setNom("Gauchoux");
        pompier.setPrenom("Xav");
        
        pompier2.setId(2);
        pompier2.setNom("Biosca");
        pompier2.setPrenom("Coco");
        
        camion.setId(1);
        camion.setPlaces(2);
        
        camion2.setId(2);
        camion2.setPlaces(1);
        
        Coordonnee c = new Coordonnee();
        c.setLatitude("1");
        c.setLongitude("1");
        
        Caserne caserne = new Caserne();
        
        caserne.setId(1);
        caserne.addCamion(camion);
        caserne.addCamion(camion2);
        caserne.addPompier(pompier);
        caserne.addPompier(pompier2);
        caserne.setCoordonnee(c);
        
        caserneRepository.save(caserneMapper.toCaserneJpa(caserne));
    }

CodePudding user response:

Thanks David you made me understand my mistake.

I used your code to add an @AfterMapping method for both my Mappers

@Mapper
public interface CaserneMapper {
    
    Caserne toCaserne(CaserneJpa caserneJpa);
    
    CaserneJpa toCaserneJpa(Caserne caserne);
    
    List<Caserne> toCaserne(List<CaserneJpa> caserneJpa);
    
    List<CaserneJpa> toCaserneJpa(List<Caserne> caserne);
    
    @AfterMapping
    default void customMapForCamionJpa(Caserne caserne, @MappingTarget CaserneJpa caserneJpa) {
        
        ArrayList<CamionJpa> listCamionJpa = (ArrayList<CamionJpa>) caserneJpa.getCamions();
        for (CamionJpa camionJpa : listCamionJpa) {
            camionJpa.setCaserne(caserneJpa);
        }
        ArrayList<PompierJpa> listPompierJpa = (ArrayList<PompierJpa>) caserneJpa.getPompiers();
        for (PompierJpa pompierJpa : listPompierJpa) {
            pompierJpa.setCaserne(caserneJpa);
        }
    }
    
    @AfterMapping
    default void customMapForListCamionJpa(List<Caserne> caserne, @MappingTarget List<CaserneJpa> caserneJpa) {
        
        for (CaserneJpa itemCaserneJpa : caserneJpa) {
            
            ArrayList<CamionJpa> listCamionJpa = (ArrayList<CamionJpa>) itemCaserneJpa.getCamions();
            for (CamionJpa camionJpa : listCamionJpa) {
                camionJpa.setCaserne(itemCaserneJpa);
            }
            ArrayList<PompierJpa> listPompierJpa = (ArrayList<PompierJpa>) itemCaserneJpa.getPompiers();
            for (PompierJpa pompierJpa : listPompierJpa) {
                pompierJpa.setCaserne(itemCaserneJpa);
            }
            
        }
        
    }
}
  • Related