Почему я получаю сообщение об ошибке при попытке вставить новый объект в БД? - PullRequest
1 голос
/ 18 января 2020

Мой сценарий выглядит следующим образом:

A Пользователь может иметь список Track , соответствующий ему, объект Track содержит идентификатор пользователя. (@OneToMany)

Каждый раз, когда создается новая дорожка, список дорожек будет обновляться.

Вышеупомянутые объекты следующие:

Трек Entity

@Entity
@Table(name ="track")
public class Track {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long trackId;

@ManyToOne
@JoinColumn(name = "userId", nullable = false)
private User user;

@OneToOne(mappedBy = "track")
private Share share;

private String trackName;

@OneToMany(mappedBy = "pointId")
private List<Point> point;

@OneToOne(mappedBy = "track")
private TrackStatistic trackStatistic;

User Entity

@Entity
@Table(name = "user")
public class User {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name = "USER_ID")
private Long id;

private String firstName;

private String lastName;

@Column(unique = true)
private String username;

private String password;

@Column(unique = true)
private String email;

@Column(unique = true)
private String phoneNumber;

private int age;

private Role role;

@OneToMany(mappedBy = "shareId")
private List<Share> shares;

@OneToMany(mappedBy = "trackId")
private List<Track> tracks;

}

createTrack метод выглядит следующим образом

public Track createTrack(String username, TrackDTO trackDTO) {
    //Find user
    User user = userRepository.findByUsername(username);

    //Convert Dto to Entity
    Track track = modelMapper.map(trackDTO, Track.class);

    //Update user track list
    user.getTracks().add(track);

    //Update track
    track.setUser(user);

    //save user
    userRepository.save(user);

    //save track
    return trackRepository.save(track);
}

Обратите внимание, что TrackDTO является соответствующим классом Dto объекта Track


Когда я запустил createTrack, я столкнулся со следующей ошибкой:

2020-01-18 20:48:23.315 ERROR 14392 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper:
 Cannot add or update a child row: a foreign key constraint fails (`thdb`.`track`, CONSTRAINT `FK5cftk3hw8vfnaigtj063skvxs` FOREIGN KEY (`track_id`) REFERENCES `user` (`user_id`))

2020-01-18 20:48:23.338 ERROR 14392 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]:
 Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause

java.sql.SQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails 
(`thdb`.`track`, CONSTRAINT `FK5cftk3hw8vfnaigtj063skvxs` FOREIGN KEY (`track_id`) REFERENCES `user` (`user_id`))

Ответы [ 4 ]

1 голос
/ 18 января 2020

Отредактировано


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

1 - добавить cascade = CascadeType.ALL к сущности пользователя

2 - добавить targetEntity = Track .class, mappedBy = "user" к сущности пользователя

3- Добавить @ManyToOne(targetEntity = User.class) @JoinColumn(name = "USER_FK") к отслеживаемой сущности

4-Удалить trackRepository.save(track);

5- Просто сохранить пользователя (userRepository.save(user)). по каскаду, он также сохраняет дорожку.

6- Возвращает последнюю дорожку в списке пользователей. (Последняя сохраненная дорожка)


Я кодировал вышеупомянутые правки как следует

объект пользователя

@Entity
@Table(name = "user")
public class User {

  //other properties

   @OneToMany(targetEntity = Track.class , mappedBy = "user" ,cascade = CascadeType.ALL)
   private List<Track> tracks;

   //getters and setters   

  }

номер объекта

@Entity
@Table(name ="track")
public class Track {

//other properties

@ManyToOne(targetEntity = User.class)
@JoinColumn(name = "USER_FK",nullable = false)
private User user;

//getters and setters

}

метод createTrack

public Track createTrack(String username, TrackDTO trackDTO) {

    //Find user
    User user = userRepository.findByUsername(username);

    //Convert Dto to Entity
    Track track = modelMapper.map(trackDTO, Track.class);

    //Update User and Track
    user.getTracks().add(track);
    track.setUser(user);

    //save user
    User result = userRepository.save(user);

    //find saved track (you can fetch track by other ways too)
    Track savedTrack = result.getTracks().get(result.getTracks().size()-1);

    return savedTrack;
}
0 голосов
/ 19 января 2020

Рефакторинг отношений между сущностями и проблема до сих пор не решена. Небольшой предварительный просмотр отношения между треком и пользователем выглядит следующим образом: Сущность трека

@Entity
@Table(name ="TRACK")
public class Track {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "TRACK_ID")
    private Long trackId;

    private String trackName;

    @OneToMany(cascade = CascadeType.ALL,
            orphanRemoval = true)
    @JoinColumn(name = "POINT_ID")
    private List<Point> point;

    @OneToOne
    @JoinColumn(name="TRACK_STATISTIC_ID")
    private TrackStatistic trackStatistic;

    private long numberOfLikes;

    private Date creationTime;

Субъект пользователя

@Entity
@Table(name = "USER")
public class User {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "USER_ID")
    private Long userId;

    private String firstName;

    private String lastName;

    @Column(unique = true)
    private String username;

    private String password;

    @Column(unique = true)
    private String email;

    @Column(unique = true)
    private String phoneNumber;

    private int age;

    private Role role;

    private boolean locked;

    private long numberOfReports;

    @JsonIgnore
    @ManyToMany()
    @JoinTable(name="FOLLOWER",
            joinColumns={@JoinColumn(name="USER_ID")},
            inverseJoinColumns={@JoinColumn(name="FOLLOWER_ID")})
    private Set<User> followed = new HashSet<User>();

    @JsonIgnore
    @ManyToMany(mappedBy="followed")
    private Set<User> follower = new HashSet<User>();

   //How it was before
    @OneToMany
    @JoinColumn(name = "TRACK_ID")
    private List<Track> tracks;

   //How is it now
    @OneToMany
    @JoinColumn(name = "USER_ID")
    private List<Track> tracks;


    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "SHARE_ID")
    private List<Share> shares;

и метод, который вызывается при создании дорожки:

public Track createTrack(String username, TrackDTO trackDTO) {
        Track track = modelMapper.map(trackDTO, Track.class);
        Track newTrack = trackRepository.save(track);
        return newTrack;
    }

Так что проблема была в аннотации @JoinColumn в списке дорожек, я поставил имя TRACK_ID вместо USER_ID

0 голосов
/ 18 января 2020

Вы должны сохранить дорожку перед пользователем.

public Track createTrack(String username, TrackDTO trackDTO) {
    User user = userRepository.findByUsername(username);
    Track track = modelMapper.map(trackDTO, Track.class);
    user.getTracks().add(track);
    track.setUser(user);
    userRepository.save(user); // 1
    return trackRepository.save(track); // 2
}

Если бы это были просто старые SQL запросы, вы бы набрали go неправильно:

  • The ( 1) запрос будет выполнять insert into USER_TRACK (<USER>, <TRACK>), но пока пользователь сохраняется, <TRACK> еще не сохранен, поэтому вы не можете назначить отношение пользователя / трека, потому что у вас нет идентификатора.
  • The ( 2) запрос будет выполнять insert into TRACK (<TRACK>) и генерировать идентификатор, но это произойдет после.

Возможно, вам не хватает отображения JPA, потому что я думаю, что JPA обычно позаботится об этом за вас.

0 голосов
/ 18 января 2020

Соотношение циклическое c, пользователь содержит дорожку (и), а дорожка содержит пользователя (ей). Существует ограничение fk в обоих направлениях, поэтому проблема. Вы можете исправить это, сохранив независимость пользователя без ссылки на трек и оставив ссылку на пользователя. Есть и другие способы исправить отношения, главное, что нужно сделать, это избежать циклических c отношений

.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...