1

I'm trying to create a Rest API for a school project.Therefor I'm trying to save/edit a nested Object. I have two bidirectional entities which look like this:

EntityA

 @Entity
    public class EntityA {
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Id
        @Column(name = "id", nullable = false)
        @JsonProperty("id")
        private int id;
    
        @Column(name = "field1", nullable = false, length = -1)
        @JsonProperty("field1")
        private String field1;
    
        @Column(name = "field2", nullable = false, length = -1)
        @JsonProperty("field2")
        private String field2;
    
        @OneToMany(mappedBy = "entityA", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
        @JsonProperty("entityB")
        private List<EntityB> entityB;
    
        public EntityA() {
    
        }
        
        //Getter+Setter
        
    }

EntityB

@Entity
public class EntityB {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(name = "id", nullable = false)
    @JsonProperty("id")
    private int id;

    @Column(name = "field1", nullable = false)
    @JsonProperty("field1")
    private Date field1;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(...)
    @JsonProperty("entityA")
    private EntityA entityA;

    public EntityB() {

    }
    
   //Getter+Setter
}

As RequestBody I will get JSON which should look like this.

{
     "field1": "Test",
     "field2": "User",
     "entityB": [
            {
                "field1": "30.03.2022"
            }
        ]
}

Right now Spring will automatically map the fields but as soon I try to save it to my DB I will get an error, because the relation in EntityB for EntityA is empty. I've seen a solution, that I should loop through the EntityB list and add EntityA. I tried it with a for-each but it still sais it null.

What am I doing wrong?

public EntityA createEntityA(EntityA entityA) {
        for(EntityB entityB : entityA.getEntityB()){
            entityB.setEntityA(entityA);
        }
        return entityARepository.save(entityA);
    }

Edit:

Controller

@PostMapping(value = {"/json/entitya/"})
@ResponseBody
public EntityA createEntityAJson(@RequestBody EntityA entityA) {
    return entityAService.createEntityA(entityA);
}

Service

@Service
public class EntityAService {

    @Autowired
    private EntityARepository entityARepository;

    public EntityA createEntityA(EntityA entityA) {
        return entityARepository.save(entityA); //in this line the error appears
    }
}

Error message

null value in column "entityA" violates not-null constraint
6
  • Can you post the error message? Commented Apr 1, 2022 at 13:05
  • @JohanNordlinder the error message sais that entityA cannot be null because of NOT-NULL restricting on the databse. If I remove this restriction the data will be saved but without relation Commented Apr 1, 2022 at 13:09
  • Is entityA.getEntityB() populated when deserialized from json? Commented Apr 1, 2022 at 13:18
  • Yes it is. I can loop through and read the field1-value of entityB but if I try to setEntityA as in my last code-snipped above it remains null. Commented Apr 1, 2022 at 13:21
  • please put the code that cause the exception and indicate the line with a comment ! is it this line return entityARepository.save(entityA); ? Commented Apr 1, 2022 at 13:21

2 Answers 2

2
@Service
public class EntityAService {
    
        @Autowired
        private EntityARepository entityARepository;
        @Autowired
        private EntityBRepository entityBRepository;
    
        public EntityA createEntityA(EntityA entityA) {

      // create an empty arrayList to stock the entities B retrieveed from the DB
       List<EnityB> lst = new ArrayList<>();
        
        // get the entities B from the JSON and sabe it to the DB    
        for(EntityB entityB : entityA.getEntityB()){
        entityB.setEntityA(entityA);
        entityBRepository.save(entityB);  // you should save entities B to the DataBase before
        Optional<EntityB > opt = entityBRepository.findById(entityB.getId());
        EntityB b = opt.get();
        
        // add the entities B retrieved from the DB to the arrayList
        lst.add(b);
        }
        
        // set the EntityB list with the new List from the DB ( include ids ..)
        entityA.setEntityB(lst);
         
        // save the entityA to the DB
            return entityARepository.save(entityA); 
        }
    }
Sign up to request clarification or add additional context in comments.

Comments

1

I'm guessing that what is happening here is that the id fields which are of a non-nullable datatype or some other hidden field from the JPA annotations get set to the wrong value by the json deserialization for JPA to understand that they are new entities. Creating these entities manually in the Java code might solve the issue.

You shouldn't reuse your entity classes as data transfer object for your API. Having classes containing both database-specific annotations and annotations for JSON serialization is a bad idea and it goes against the single-responsibility principle (SRP).

Create separate DTO classes for your API endpoint, then read the entities from the database an copy the values from the DTO object to the entities before saving.

// Receive DTO
// Read entity from DB if update or create new entities if insert
// Copy values from DTO to entitiy
// Save entity

I think your problems will go away if you apply this pattern.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.