简体   繁体   中英

Many to many relationship using spring boot not saving data to join table

I have a many to many relationship between users and questions for favouriting items, and when I trigger my /questionId/favourite api for a user, it should create an entry under the join table question_favourite that would map out user_id and question_id (which are both called 'id' within their own table).

I see the question_favourite table has been created, but it's always empty. I tried also using a put rather than post thinking that perhaps that's why I don't see an insert statement printed on the console but it didn't help much and I think I'm a bit stuck now.

I see similar questions posted here but being a beginner on Spring and having spent literally a few months now trying to figure out why I can't save data to my join table, I thought I'd need some more specific help please.

Here is what I have:

@Entity
@Table(name = "user_profile")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
public class UserEntity {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "userEntity", cascade = CascadeType.ALL, orphanRemoval = true)
private Collection<QuestionEntity> questionEntities;

@ManyToMany
@JoinTable(
        name = "question_favourite",
        joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "question_id", referencedColumnName = "id"))
private Set<QuestionEntity> questionFavouriteEntity;


public UserEntity(UUID id) {
    this.id = id;
}

}


@Entity
@Table(name = "question")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)

public class QuestionEntity {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;

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

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
@JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
private UserEntity userEntity;

@ManyToMany(mappedBy = "questionFavouriteEntity")
private Set<UserEntity> userEntities;

public QuestionEntity(UUID id) {
    this.id = id;
}

public QuestionEntity(UUID id, String title) {
    this.id = id;
    this.title = title;
}

}


@PostMapping(value = "/{id}/favourite", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<QuestionFavouriteCreateDto> setFavouriteQuestion(@RequestHeader(required = false, value = "authorization") UUID userId, @RequestBody QuestionFavouriteCreateDto questionFavouriteCreateDto) {

    if (userId == null) {
        return new ResponseEntity<>(HttpStatus.FORBIDDEN);
    } else {
        return new ResponseEntity<>(questionCommandService.favouriteQuestion(userId, questionFavouriteCreateDto), HttpStatus.OK);
    }
}

@Override
public QuestionFavouriteCreateDto favouriteQuestion(UUID userId, QuestionFavouriteCreateDto qf) {

    if (questionRepository.findById(qf.getQuestionId()).isPresent()) {
        QuestionEntity questionEntity = questionRepository.findById(qf.getQuestionId()).get();
        UserEntity userEntity = userRepository.findById(userId).get();

        questionEntity.getUserEntities().add(userEntity);
        userEntity.getQuestionEntities().add(questionEntity);

        userRepository.save(userEntity);
        questionRepository.save(questionEntity);
        
        return new QuestionFavouriteCreateDto(questionEntity.getId(), true);
    } else {
        return null;
    }
}

Here is the github link for the project: https://github.com/francislainy/so/tree/master/backend/src/main/java/com/francislainy/so/backend

Thank you very much.

In your class QuestionCommandServiceImpl you should add a set of the question entity created as a Question Favourite like bellow:

  @Override
    public QuestionFavouriteCreateDto favouriteQuestion(UUID userId, QuestionFavouriteCreateDto qf) {

        if (questionRepository.findById(qf.getQuestionId()).isPresent()) {
            QuestionEntity questionEntity = questionRepository.findById(qf.getQuestionId()).get();
            UserEntity userEntity = userRepository.findById(userId).get();

            questionEntity.getUserEntities().add(userEntity);
            userEntity.getQuestionEntities().add(questionEntity);
            userEntity.getQuestionFavouriteEntity().add(questionEntity); // get the Set of favorite question and add the new question
            userRepository.save(userEntity);

        }

        return null;
    }

But preferably in the your case you can remplace in UserEntity the @OneToMany by joinColumn it's more perform:

  @OneToMany(fetch = FetchType.LAZY, mappedBy = "userEntity", cascade = CascadeType.ALL, orphanRemoval = true)
    private Collection<QuestionEntity> questionEntities;

and try to unused the bidirectional or use with them the @JacksonBackReference

I hope that's help you;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM