5

I'm trying to use spring data CrudRepository to persist a parent entity that includes a few child entities, however I'm having trouble getting the foreign key constraint OID in the child table to save when I "save" the parent.

So in the example below a call to the controller with the provided JSON would persist an Ocean and the 2 child Fish. However the FK OID in the Fish table isn't being set.

Starting with the JSON request to the controller here is the code. JSON REQUEST

{
     "name":"Atlantic",
     "fishes": [
     {
         "name": "blue fin tuna"
     },
     {
        "name": "great white shark"
     }
     ]
}

OCEAN ENTITY

@Entity
public class Ocean {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long oid;
private String name;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = 
"ocean")
private Set<Fish> fishes; //yeah maybe a  bad example

FISH ENTITY

@Entity
public class Fish {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long fid;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "oid", nullable = false, updatable = false, insertable = 
true)
private Ocean ocean;
private String name;

CONTROLLER

@PostMapping("/god/ocean")
public Ocean createOcean(@RequestBody Ocean ocean) throws BadRequestException 
{
    LOG.info("createOcean()");
    return oceanDao.save(ocean);
}

REPOSITORY

public interface IOceanDao extends CrudRepository<Ocean, Long> {
}

MySql TABLES

CREATE TABLE IF NOT EXISTS `mydb`.`OCEAN` (
`OID` INT NOT NULL AUTO_INCREMENT COMMENT '',
`NAME` VARCHAR(45) NOT NULL COMMENT '',
 PRIMARY KEY (`OID`)  COMMENT '');

CREATE TABLE IF NOT EXISTS `mydb`.`FISH` (
`FID` INT(11) NOT NULL AUTO_INCREMENT COMMENT '',
`OID` INT(11) NULL  COMMENT '',
`NAME` VARCHAR(45) NOT NULL COMMENT '',
PRIMARY KEY (`FID`)  COMMENT '',
CONSTRAINT `FK_OID`
FOREIGN KEY (`OID`)
REFERENCES `mydb`.`OCEAN` (`OID`));
kingpia
  • 63
  • 1
  • 6

2 Answers2

9

I was getting the same problem until JsonManagedReference came to my rescue.

Try changing your entities to include them like this:

In the Ocean Entity:

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = 
"ocean")
@JsonManagedReference
private Set<Fish> fishes;

In the Fish Entity:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "oid", nullable = false, updatable = false, insertable = 
true)
@JsonBackReference
private Ocean ocean;

I was not able to find why it works this way, so please let me know if you come to know :)

Saksham Gupta
  • 380
  • 5
  • 12
0

Use CascadeType.PERSIST to let EntityManager automatically persist all your Child entities, please try changing Ocean entity as below

@Entity
public class Ocean {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long oid;

private String name;    
@OneToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER, mappedBy ="ocean")
private Set<Fish> fishes;
gvk
  • 156
  • 1
  • 8
  • Alternate way of doing this is to save the parent first and then save the children all in a single transaction. – gvk Jun 08 '18 at 13:40
  • 2
    hmm. I gave adding the CascadeType.PERSIST a try but still no go. It's still leaving the OID null. As for saving the parent first then the children, thats actually the work around I'm doing for now, but it seams like it would be cleaner if I could get the whole entity to save with one .save call. I just feel like I'm lacking understanding of some underlying functionality. – kingpia Jun 08 '18 at 20:00
  • I referred the link (https://stackoverflow.com/questions/3927091/save-child-objects-automatically-using-jpa-hibernate/3930071) and it worked for me. – Bharadwaj P N Jul 06 '21 at 13:40