问题
I have 3 Tables in db
training
- training_id (pk)
user_profile
- profile_id (pk)
-training_profile (composite table)
- training_id
- profile_id
I have already record in user_profile table having profile_id=44 and want to create new record for training table ,and also to associate this new training with already existing user_profile record which has id 44,but after post data is saved to training table but it is not inserted into lookup table user_training.
My Object Classes Are
- Training Class
@Entity
@Table(name = "training", schema = "public")
public class Training implements java.io.Serializable {
@Id @GeneratedValue
@Column(name = "training_id", unique = true, nullable = false)
private Long trainingId;
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "trainings")
private Set<UserProfile> userProfiles = new HashSet<UserProfile>(0);
@Column(name = "training_subject", length = 200)
private String trainingSubject;
public Training() {
}
public Long getTrainingId() {
return this.trainingId;
}
public void setTrainingId(Long trainingId) {
this.trainingId = trainingId;
}
public String getTrainingSubject() {
return this.trainingSubject;
}
public void setTrainingSubject(String trainingSubject) {
this.trainingSubject = trainingSubject;
}
public Set<UserProfile> getUserProfiles() {
return this.userProfiles;
}
public void setUserProfiles(Set<UserProfile> userProfiles) {
this.userProfiles = userProfiles;
}
}
UserProfile
@Entity @Table(name = "user_profile", schema = "public")
public class UserProfile implements java.io.Serializable {@Id @GeneratedValue @Column(name = "profile_id", unique = true, nullable = false) private Long profileId; @Column(name = "profile_description") private String profileDescription; @ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }) @JoinTable(name = "user_training", schema = "public", joinColumns = { @JoinColumn(name = "profile_id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "training_id", nullable = false, updatable = false) }) private Set<Training> trainings = new HashSet<Training>(0); public UserProfile() { } public String getProfileDescription() { return this.profileDescription; } public void setProfileDescription(String profileDescription) { this.profileDescription = profileDescription; } public Set<Training> getTrainings() { return this.trainings; } public void setTrainings(Set<Training> trainings) { this.trainings = trainings; }
}
My json post via postman
And Response I get
Response show that new training record inserted in table having training_id as 67 No association found for this new saved training
again it created new record for training and does not associate with existing user profile , I post curl -i -X POST -H "Content-Type:application/json" -d "{ \"trainingSubject\" : \"Oracle\", \"userProfiles\":[\"/userProfiles/44\"] }" http://localhost:8080/api/trainings
回答1:
You could use the relative url assignment:
{
"trainingSubject": "oracle",
"userProfiles":["/userProfiles/44"]
}
Maybe also try with the full url: http://localhost:8080/api/userProfiles/44
EDITED
If you move the owning site of the ManyToMany
relation to Training
it will work with the above JSON. So currently the owner is allowed to set the realtions. If you do it like that:
@ManyToMany
@JoinTable(name = "user_training"
, joinColumns = {@JoinColumn(name = "profile_id") }
, inverseJoinColumns = {@JoinColumn(name = "training_id") })
private List<UserProfile> userProfiles = new ArrayList<>();
plus
@ManyToMany(mappedBy = "userProfiles")
private List<Training> trainings = new ArrayList<>();
Training
owns the relation within userProfiles
.
I think in your case it's the best option for now. Another option would be, when keeping the owner site at UserProfile
on transactions
, to update the relation there like:
PATCH http://localhost:8080/api/userProfiles/44
{
"trainings": ["trainings/66", "trainings/67"]
}
But with this you would need multible rest calls (1. POST new training and get the new Id 2. GET current training list 3. PATCH trainings list with newly added training)
Last option would be to add the REST-controller on your own.
Complete files for the first approach:
@Entity
@Table
public class Training implements Serializable {
@Id
@GeneratedValue
private Long trainingId;
@ManyToMany
@JoinTable(name = "user_training"
, joinColumns = {@JoinColumn(name = "profile_id") }
, inverseJoinColumns = {@JoinColumn(name = "training_id") })
private List<UserProfile> userProfiles = new ArrayList<>();
@Column(name = "training_subject", length = 200)
private String trainingSubject;
@Entity
@Table
public class UserProfile implements Serializable {
@Id
@GeneratedValue
private Long profileId;
@Column(name = "profile_description")
private String profileDescription;
@ManyToMany(mappedBy = "userProfiles")
private List<Training> trainings = new ArrayList<>();
public interface TrainingRepository extends JpaRepository<Training, Long> {
}
public interface UserProfileRepository extends JpaRepository<UserProfile, Long> {
}
With the upper JSON this will work, I tested it. You will not see the correct result directly in the response of curl-POST. To see the added relation you must follow the userProfiles
-link like GET http://localhost:8080/transactions/<newId>/userProfiles
来源:https://stackoverflow.com/questions/43111692/unable-to-save-data-to-composite-table-via-spring-data-rest-json-post