Hibernate не вставляет дочерние объекты: Hibernate: выберите nextval ('hibernate_sequence') - PullRequest
1 голос
/ 09 июля 2020

У меня четыре класса: Alien, AlienAppartment, AlienBuilding и AlienBedroom. Все они имеют отношение ManyToOne:

Alien -> has many AlienBuilding -> has many AlienAppartment -> has many AlienBedroom

Я пытаюсь вставить JSON с объектом AlienBuilding через этот контроллер:

AlienController. java:

@CrossOrigin
@RestController
public class AliensController {
    @Autowired
    private AlienBuildingRepository alienBuildingRepository;
    @Autowired
    private AlienRepository alienRepository;
    @Autowired
    private AlienBedroomRepository alienBedroomRepository;
    @Autowired
    private AlienAppartmentRepository alienAppartmentRepository;
    
    ...
 
    @GetMapping("/api/aliens/buildings/insert")
    @Transactional
    public String insertBuilding(
                    @RequestBody AlienBuilding alienBuilding)  {
     alienBuildingRepository.save(alienBuilding);

     return "OK";
    }
}

JSON:

{"id":null,"alien":{"id":null,"name":"some alien"},"appartments":[{"id":null,"alienBedrooms":[{"id":null,"description":"cool"}]}]}

Однако все, что я получаю, это

Hibernate: select nextval ('hibernate_sequence')

вывод в консоли . Однако в отладчике я вижу, что JSON был сопоставлен с объектом AlienBuilding.

Я могу попытаться заставить его вставить некоторые вещи через

    @GetMapping("/api/aliens/buildings/insert")
    @Transactional
    public String insertBuilding(
                    @RequestBody AlienBuilding alienBuilding)  {
        //alienBuildingRepository.save(alienBuilding);

        alienRepository.save(alienBuilding.getAlien());
        for (AlienAppartment appartment: alienBuilding.getAppartments())  {
            for (AlienBedroom bedroom: appartment.getAlienBedrooms())  {
                alienBedroomRepository.save(bedroom);
                alienBedroomRepository.flush();
            }

            alienAppartmentRepository.save(appartment);
            alienAppartmentRepository.flush();
        }

        alienBuildingRepository.save(alienBuilding);
        alienBuildingRepository.flush();

        return "OK";
    }

, и я бы получите этот вывод:

Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into aliens (name, id) values (?, ?)
Hibernate: insert into alien_bedrooms (appartment_id, description, id) values (?, ?, ?)
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into alien_appartments (building_id, id) values (?, ?)
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into alien_buildings (alien_id, id) values (?, ?)

Но building_id столбец в alien_appartments таблице будет пуст, как и столбец appartment_id в alien_bedrooms таблице

Это мои объекты:

Чужой. java:

@Entity
@Table(name = "aliens")
public class Alien  {
    @Id @GeneratedValue
    private int id;

    public Alien()  {}

    @Column
    private String name;

    @OneToMany(mappedBy = "alien", fetch=FetchType.EAGER)
    @JsonIgnore
    private Set<AlienBuilding> buildings;

    /**
     * Getters,setters
     */

Чужой. java:


@Entity
@Table(name = "alien_appartments")
public class AlienAppartment {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO )
    public Long id;

    public AlienAppartment() {
    }

    @OneToMany(mappedBy = "appartment", fetch = FetchType.EAGER,
                        cascade = CascadeType.ALL)
    private Set<AlienBedroom> alienBedrooms;

    @ManyToOne
    @JoinColumn(name = "building_id")
    @JsonIgnore
    private AlienBuilding building;


    /**
     * Getters,setters
     */

AlienBedroom. java:

@Entity
@Table(name = "alien_bedrooms")
public class AlienBedroom {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO )
    private Long id;

    public AlienBedroom()  {}

    @Column
    private String description;

    @ManyToOne
    @JoinColumn(name = "appartment_id")
    @JsonIgnore
   private AlienAppartment appartment;

    /**
     * Getters,setters
     */

AlienBuilding. java:

@Entity
@Table(name = "alien_buildings")
public class AlienBuilding {
    @Id
    @GeneratedValue
    public Long id;

    public AlienBuilding() {
    }

    @ManyToOne
    @JoinColumn(name = "alien_id")
    private Alien alien;

    @OneToMany(mappedBy = "building", fetch = FetchType.EAGER)
    private Set<AlienAppartment> appartments;

    /**
     * Getters, setters
     */

Хранилища :

@Repository
public interface AlienAppartmentRepository extends
                JpaRepository<AlienAppartment, Long> {
}

@Repository
public interface AlienBedroomRepository extends JpaRepository<AlienBedroom, Long> {
}

@Repository
@Transactional(value = "transactionManager", propagation = Propagation.REQUIRED)
public interface AlienBuildingRepository
        extends JpaRepository<AlienBuilding, Long> {
}

@Repository
@Transactional(value = "transactionManager", propagation = Propagation.REQUIRED)
public interface AlienRepository extends JpaRepository<Alien, Long> {
}

1 Ответ

0 голосов
/ 10 июля 2020

Я заставил это работать так:

  1. Я добавил cascade = CascadeType.ALL ко всему:
public class Alien  {
...
    @OneToMany(mappedBy = "alien", fetch=FetchType.EAGER, cascade = CascadeType.ALL)
    @JsonIgnore
    private Set<AlienBuilding> buildings;
...
}
public class AlienAppartment  {
...
@OneToMany(mappedBy = "appartment", fetch = FetchType.EAGER,
                        cascade = CascadeType.ALL)
    private Set<AlienBedroom> alienBedrooms;
...
}

et c

и

Я убедился, что сторона Many отношения OneToMany имеет ссылку на сторону One. Это необходимо, потому что, скажем, если я вставлю здание, если в нем есть ссылка на инопланетянина, то инопланетянин тоже будет вставлен. Поскольку инопланетянин является стороной One, ему не нужна ссылка на его родительский объект building, который его содержит. Однако зданию нужна ссылка на пришельца - как для запуска вставки, так и потому, что идентификатор пришельца составляет часть таблицы, связанной со строительным объектом. Аналогично, поскольку bedroom - это сторона Many соединения @OneToMany с appartment (одна квартира имеет много спален, каждая спальня имеет только одну квартиру), а appartment_id является частью таблицы bedrooms, спальня должна содержать ссылку на квартиру:
@GetMapping("/api/aliens/buildings/insert")
    @Transactional(value="transactionManager", readOnly=false, propagation =  Propagation.REQUIRED)
    public String insertBuilding(
                    @RequestBody AlienBuilding alienBuilding)  {
        for (AlienAppartment appartment: alienBuilding.getAppartments())  {
            appartment.setBuilding(alienBuilding);

            for (AlienBedroom bedroom: appartment.getAlienBedrooms())  {
                bedroom.setAppartment(appartment);
            }
        }

        alienBuildingRepository.save(alienBuilding);
        alienBuildingRepository.flush();

        return "OK";
    }

И JSON я отправляю:

{"id":null,"alien":{"id":null,"name":"awesome alien"},"appartments":[{"id":null,"alienBedrooms":[{"id":null,"description":"awesome bedroom"}]}]}

Как все выглядит в справочнике отладчика -wise (точка останова устанавливается в строке alienBuildingRepository.save(alienBuilding);, прямо перед вставкой здания в контроллер):

введите описание изображения здесь

...