Объект сохранения гибернации (отношение «один ко многим») внешний ключ равен нулю

#java #spring #hibernate #jpa #bidirectional

#java #гибернация #остальное #джакарта-ee #http-post

Вопрос:

У меня есть отношения «один ко многим» между классом person и классом car. У человека может быть много автомобилей и наоборот. Я использую restful API для публикации данных. Мои аннотации и служба получения работают нормально, но моя служба post выдает » java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL" error всякий раз, когда я пытаюсь вставить новые данные. Дочерняя таблица foreign key вставляется как null .

Вот часть моего кода.

Person.java

  private List<Car> cars = new ArrayList<Car>();

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="person")    
@JsonManagedReference
public List<Car> getCars() {
  return cars;
 }
  

Car.java

 private Person person;  

    @ManyToOne
    @JoinColumn(name = "PERSON_ID", nullable = false, updatable = true, insertable = true)
    @JsonBackReference
    public Person getPerson() {
        return person;
    }
  

Мой класс обслуживания:

 @POST
        @Path("/PersonRegistration")
        @Consumes(MediaType.APPLICATION_JSON)
        public Response postPersonCars(Person person) throws Exception{

            Session session = null;     
            ObjectMapper mapper = new ObjectMapper();   
            //Person per = new Person();
            //Car cars = new Car();
            try{
                session = HibernateUtil.getSessionFactory().openSession();
                session.beginTransaction(); 
                //per.setCars(person.getCars());
                session.save(person);
                session.getTransaction().commit();

            }catch(Exception e){
                e.printStackTrace();
                throw e;
            }finally{
                if(null != session){
                    session.close();
                }
            }

            return Response.status(201).entity(mapper.writeValueAsString(person)).build();
        }
  

Ответ №1:

Эта аннотация:

 @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="person")
  

имеет два последствия:

  1. mappedBy подразумевает, что Car это сторона-владелец отношения. Это означает, что всякий раз, когда вы хотите установить связь между Car и Person , вам нужно сделать это, установив Car.person для свойства соответствующее значение. Изменения в Person.cars режиме гибернации будут проигнорированы.
  2. cascade=CascadeType.ALL означает, что всякий раз, когда вы сохраняете a Person , Hibernate также будет вызывать операцию сохранения для всех объектов, содержащихся в Person.cars

Результат: вы вызываете Session.save() группу Car объектов, для которых Car.person свойство не установлено должным образом.

Решение: либо измените сторону владельца отношения (имейте в виду, что вам также понадобится @JoinColumn on Person.cars , если вы не хотите, чтобы создавалась дополнительная таблица базы данных), либо выполните цикл Person.cars и Car.person правильно установите свойство в каждом из них.

cascade=CascadeType.ALL предполагает, что первое решение лучше подходит для вашего варианта использования.

Комментарии:

1. Спасибо crizzis за ваш ответ. Я вызываю session.save для объекта person, у которого есть ArrayList автомобилей. Итак, я должен повторить json и установить cars на Person?

2. Вы должны перебирать person.getCars() и вызывать car.setPerson(person) каждый car

3. Итак, для удаления мне тоже нужно сделать то же самое? перебрать person.getCars и удалить car, а затем person? Это хороший подход или я что-то упускаю?

4. Нет. В этом случае должно быть достаточно удаления person, поскольку CascadeType.ALL будет каскадное удаление