Сохранение двух объектов одновременно с отношениями OneToOne - PullRequest
0 голосов
/ 12 октября 2019

Я уже давно пытаюсь решить эту проблему, но я никуда не попал. Я пытался сохранить сущность, которая имеет ссылку на другую сущность.

Пользователь создает объект размещения, заполнив форму, а затем нажимает сохранить, чтобы сохранить ее. Он должен автоматически создавать новые строки в таблицах ' place ' и ' place_urls '. Вот ссылка на файл SQL, который я загружаю в приложение: https://pastebin.com/x8Gvk7ub

Родительский объект:

@Entity
@Table(name="places")
public class Place {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id", nullable=false, updatable=false)
    private Long id;

    @Column(name="userId")
    private Long userId;

    @Column(name="name", nullable=false, unique=true)
    private String name;

    @Column(name="address", nullable=false)
    private String address;

    @Column(name="largeDescription", nullable=false)
    private String largeDescription;

    @Column(name="smallDescription", nullable=false)
    private String smallDescription;

    @OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="id")
    private PlaceUrl placeUrl;

    @OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="id")
    private List<Booking> bookings;

    getters and setters...
}

Дочерний объект:

@Entity
@Table(name="placeUrls")
public class PlaceUrl {

    @Id
    @Column(name="id", nullable=false, updatable=false)
    private Long id;

    @Column(name="placeId", nullable=false, updatable=false)
    private Long placeId;

    @Column(name="url", nullable=false, updatable=true, unique=true)
    private String url;

    @OneToOne
    @JoinColumn(name="id", referencedColumnName="placeId")
    private Place place;

    getters and setters...
}

Контроллер:

@PostMapping("/place/add")
public String addPlace(@ModelAttribute Place place, @AuthenticationPrincipal UserDetails currentUser) {
     User user = userRepository.findUserByUsername(currentUser.getUsername());
     place.setUserId(user.getId());
     placeRepository.save(place);
     return "redirect:/places";
}

Именование Hibernate установлено в implicitic-strategy в application.properties

ОБНОВЛЕНИЕ :

Место объекта:

@OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="place")
private PlaceUrl placeUrl;

Объект PlaceUrl:

Removed the placeId column, placeId variable and it's getters and setters.

@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="placeId")
private Place place;

Изменения контроллера:

@PostMapping("/place/add")
public String addPlace(@ModelAttribute Place place, @AuthenticationPrincipal UserDetails currentUser) {
User user = userRepository.findUserByUsername(currentUser.getUsername());
    place.setUserId(user.getId());
    place.getPlaceUrl().setUrl("something_nice");
    placeRepository.save(place);
    return "redirect:/places";
}

Теперь при сохранении я получаю: No message available java.lang.NullPointerException

ОБНОВЛЕНИЕ 2 :

Я начал работать, просто бездельничая. Я понятия не имею, почему это работает, поэтому кто-то другой может объяснить.

@PostMapping("/place/add")
    public String addPlace(Model model, @ModelAttribute Place place, @AuthenticationPrincipal UserDetails currentUser) {
        PlaceUrl placeUrl = new PlaceUrl();
        User user = userRepository.findUserByUsername(currentUser.getUsername());
        placeUrl.setUrl(place.getName());
        place.setPlaceUrl(placeUrl);
        place.setUserId(user.getId());
        placeUrl.setPlace(place); <-- this line here made it all work
        placeRepository.save(place);
        return "redirect:/places";
    }

Я следовал инструкциям руководства, которое мне предложили. По сути, я добавил @OneToOne (mappedBy = "place") к родителю, затем добавил @OneToOne и @JoinColumn (name = "placeId") к дочерней сущности.

1 Ответ

1 голос
/ 12 октября 2019

Вы уже отображаете связь в родительской сущности, но не используете ее в дочерней. Вместо этого, определяя другое сопоставление, вы не можете использовать преимущества каскадирования. Решением было бы добавить mappedBy в PlaceUrl:

@OneToOne(mappedBy = "placeUrl")
private Place place;

или, что еще лучше, использовать mappedBy на стороне ребенка, что является подходом clean .

...