One-to-One Relationship in Spring JPA does not migrate the foreign key

1

I have two entities in my Spring Boot project that uses Spring JPA and a MySQL database with Hibernate. These two entities are related to a One to One relationship. The problem is that when I try to add a type of objects, the primary key of the other related object is not migrated.

This is one of my entities:

@Entity
@DynamicUpdate
@Table(name = "tank")
public class Tank {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToOne(cascade=CascadeType.ALL)
    @JoinColumn(name = "level_sensor_id")
    private LevelSensor levelSensor;

    public LevelSensor getLevelSensor() {
        return levelSensor;
    }

    public void setLevelSensor(LevelSensor levelSensor) {
        this.levelSensor = levelSensor;
    }
}

And this is the other entity:

@Entity
@DynamicUpdate
@Table(name = "level_sensor")
public class LevelSensor {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToOne(mappedBy="levelSensor", cascade=CascadeType.PERSIST)
    private Tank tank;
}

I am trying to add a new LevelSensor to an existing Tank. For this I have the following driver:

@RequestMapping(value="/levelSensor/", method = RequestMethod.POST, produces = "application/json")
    @ResponseBody
    public ResponseEntity<Object> addLevelSensor(           
            @RequestBody LevelSensorDTO levelSensorDTO,
            @RequestHeader("Accept") String acceptHeader, HttpSession session) {

        LevelSensor newLevelSensor= new LevelSensor();

        Tank tank = tankService.getTankById(levelSensorDTO.getTankId());

        newLevelSensor.setTank(tank);

        newLevelSensor = levelSensorService.saveLevelSensor(newLevelSensor);        

        log.info("The level sensor : "+ levelSensorDTO.toString() +" was successfully added");

        return new ResponseEntity<Object>(null ,HttpStatus.OK);
    }

Even though I tell the LevelSensor what its tank is, it does not fill the external relationship in the Tank, so it creates the LevelSensor but it is not related to the Tank.

It can be corrected, for this, what I can do is, once the level sensor is added, I can edit the tank and assign it the newly created level sensor. However it is a solution that I do not like and that I do not understand since then I have to edit two objects when I think that editing one should be enough.

Could you help me out or advise me? Could it be that the relationship is wrong?

Thank you very much in advance.

Javier.

    
asked by cjbs 24.11.2017 в 12:45
source

1 answer

1

When you have a "one to one" relationship, jpa by default considers that the fetchType is "eager", this means that the daughter entity is loaded in the parent entity by default. To define your relationship well, you have to define which is the parent entity of the relationship and which is the daughter. In the case of the parent entity is where you make the mappedBy and the cascade within your @OneToOne and in this cascade is where your error is. You are putting it in the two entities (and I intuit from the code that your relationship is not bidirectional because you are treating your LevelSensor entity as the parent).

In one entity you are declaring cascade=CascadeType.ALL and in the other cascade=CascadeType.PERSIST

The Cascade attribute what it does is tell jpa how it should behave in the relationship between the parent entity and the daughter entity, therefore, by saying that the cascadeType is persist implies that it only "uses" the relationship between the two entities at the time of persisting in database and not in the rest of operations. The ideal is to use the all in this entity to consider that attribute as a daughter entity in the rest of operations also, you can find more info about this property here: link

With this done, I will tell you that hibernate knows perfectly how to treat your child entity and (simply having that attribute filled with an existing id) jpa knows perfectly how to map that relationship and will give you the corresponding exception in case you try to violate it.

    
answered by 24.11.2017 / 14:09
source