#spring #spring-boot #spring-mvc #jpa #spring-data-jpa
#Spring #spring-boot #spring-mvc #jpa #spring-data-jpa
Вопрос:
У меня есть две сущности User и Focus, для которых я должен сохранить рейтинг таким образом, чтобы у пользователя мог быть рейтинг для многих фокусов, а у фокуса может быть много пользователей. Чтобы справиться с этим, я следовал https://www.baeldung.com/jpa-many-to-many часть 3, в которой у меня есть 2 следующих класса:
@Entity(name = "UserBaseRatings")
public class Rating {
@EmbeddedId
RatingKey id;
@ManyToOne
@MapsId("userID")
@JoinColumn(name="userID")
private User user;
@ManyToOne
@MapsId("focusID")
@JoinColumn(name="focusID")
private Focus focus;
private BigDecimal baseRating;
protected Rating(){}
public Rating(User user, Focus focus, BigDecimal baseRating) {
this.user = user;
this.focus = focus;
this.baseRating = baseRating;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Focus getFocus() {
return focus;
}
public void setFocus(Focus focus) {
this.focus = focus;
}
public BigDecimal getBaseRating() {
return baseRating;
}
public void setBaseRating(BigDecimal baseRating) {
this.baseRating = baseRating;
}
}
и
@Embeddable
public class RatingKey implements Serializable {
@Column(name="userID")
private Long userID;
@Column(name="focusID")
private Long focusID;
protected RatingKey(){}
public RatingKey(Long userID, Long focusID) {
this.userID = userID;
this.focusID = focusID;
}
public Long getUserID() {
return userID;
}
public void setUserID(Long userID) {
this.userID = userID;
}
public Long getFocusID() {
return focusID;
}
public void setFocusID(Long focusID) {
this.focusID = focusID;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RatingKey ratingKey = (RatingKey) o;
return Objects.equals(userID, ratingKey.userID) amp;amp;
Objects.equals(focusID, ratingKey.focusID);
}
@Override
public int hashCode() {
return Objects.hash(userID, focusID);
}
}
Таблица для пользовательских настроек имеет значение по умолчанию 1 для базовой настройки, так что, если у пользователя нет рейтинга в текущем фокусе, его рейтинг должен быть равен 1. Я сталкиваюсь с проблемой, когда, если пользователь не установил рейтинг, набор рейтингов пуст вместо того, чтобы иметь рейтинг 1 для каждого существующего фокуса.
Пользователь:
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long userID;
@Column(name = "userHashedPassword")
private String password;
@Column(name = "userName")
private String userName;
@Column(name = "userEmail")
private String email;
//probably being reset
@Transient
private List<String> groups = new LinkedList<>();
@ManyToMany
@JoinTable(name = "UserRoles",
joinColumns = @JoinColumn(
name = "userID"),
inverseJoinColumns = @JoinColumn(
name = "roleID"))
private Set<Role> roles = new HashSet<>();
@OneToMany(mappedBy = "user")
private Set<Rating> ratings;
protected User(){}
public User(String userHashedPassword, String userName, String email, Set<Role> roles){
this.password = userHashedPassword;
this.userName = userName;
this.email = email;
this.roles = roles;
}
public Long getUserId() {
return userID;
}
public void setId(Long userID) {
this.userID = userID;
}
public String getPassword(){
return password;
}
public void setPassword(String password){
this.password = password;
}
public String getUsername() {
return userName;
}
public void setUsername(String name) {
this.userName = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public Set<Rating> getRatings() {
return ratings;
}
public void setRatings(Set<Rating> ratings) {
this.ratings = ratings;
}
}
Focus:
@Entity
public class Focus {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long focusID;
private String focusCategory;
private String focusName;
private String focusExplanation;
@OneToMany(mappedBy = "focus")
Set<Rating> ratings;
//image
protected Focus(){}
public Focus(String focusCategory, String focusName, String focusExplanation, Set<Rating> ratings){
this.focusCategory = focusCategory;
this.focusName = focusName;
this.focusExplanation = focusExplanation;
this.ratings = ratings;
}
public Long getFocusId() {
return focusID;
}
public void setFocusId(Long focusID) {
this.focusID = focusID;
}
public String getFocusCategory() {
return focusCategory;
}
public void setFocusCategory(String focusCategory) {
this.focusCategory = focusCategory;
}
public String getFocusName() {
return focusName;
}
public void setFocusName(String focusName) {
this.focusName = focusName;
}
public String getFocusExplanation() {
return focusExplanation;
}
public void setFocusExplanation(String focusExplanation) {
this.focusExplanation = focusExplanation;
}
public Set<Rating> getRatings() {
return ratings;
}
public void setRatings(Set<Rating> ratings) {
this.ratings = ratings;
}
}
Чего мне не хватает, что позволит заполнять оценки пользователя значением по умолчанию для каждого фокуса, существующего в базе данных?
Редактировать: добавлены @prePersist и @preUpdate к объекту оценки:
@Entity(name = "UserBaseRatings")
public class Rating {
@EmbeddedId
RatingKey id;
@ManyToOne
@MapsId("userID")
@JoinColumn(name="userID")
private User user;
@ManyToOne
@MapsId("focusID")
@JoinColumn(name="focusID")
private Focus focus;
private BigDecimal baseRating;
protected Rating(){}
public Rating(User user, Focus focus, BigDecimal baseRating) {
this.user = user;
this.focus = focus;
this.baseRating = baseRating;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Focus getFocus() {
return focus;
}
public void setFocus(Focus focus) {
this.focus = focus;
}
public BigDecimal getBaseRating() {
return baseRating;
}
public void setBaseRating(BigDecimal baseRating) {
this.baseRating = baseRating;
}
@PrePersist
public void prePersist() {
if(baseRating == null) {
baseRating = BigDecimal.ONE;
}
}
@PreUpdate
public void preUpdate() {
if(baseRating == null) {
baseRating = BigDecimal.ONE;
}
}
}
Изменение spring.jpa.hibernate.ddl-auto=
с none
на update
также не имело никакого значения.
Ответ №1:
Если вы используете ORM, все значения по умолчанию должны быть явно объявлены. Это можно сделать следующим образом
@Entity(name = "UserBaseRatings")
public class Rating {
// ...
private BigDecimal baseRating = BigDecimal.ONE;
// ...
}
или используйте @PrePersist
и @PreUpdate
@Entity(name = "UserBaseRatings")
public class Rating {
// ...
private BigDecimal baseRating;
// ...
@PrePersist
public void prePersist() {
if(baseRating == null) {
baseRating = BigDecimal.ONE;
}
}
@PreUpdate
public void preUpdate() {
if(baseRating == null) {
baseRating = BigDecimal.ONE;
}
}
}
Комментарии:
1. Я добавил аннотации prePersist и preUpdate, однако это не имело никакого значения. Возможно, мое понимание встроенных классов неверно — я думал, что он заполнит таблицу рейтингов, сущность и, следовательно, рейтинг пользователя, установленный при запуске на основе идентификатора пользователя и идентификатора фокуса (ранее существовавших объектов / таблиц). Что мне нужно сделать, чтобы это было так?
2. Ах, я не сохраняю его, и именно поэтому он не будет генерировать таблицы в БД. Однако в моем случае, где я должен сохранять объект? Мне нужен объект ранжирования, созданный для каждого ранее существующего пользователя и Focus, нужно ли мне вручную использовать репозиторий user и focus для поиска записей таблицы при запуске, а затем создавать и сохранять рейтинги из этого? Я думал, что этот процесс будет автоматически выполнен Spring
3. Я неправильно понял вашу проблему. Вы хотите заставить Spring генерировать столбец таблицы со значением по умолчанию?
4. Я хочу, чтобы Spring автоматически генерировал рейтинг для каждого существующего пользователя и фокусировки, например, если у меня есть User: Bob и Focus: Maths и Focus: Science, я бы хотел, чтобы Spring создал рейтинг с идентификатором пользователя Боба mathsID и рейтинг с идентификатором пользователя Боба scienceID все со значением по умолчаниюиз 1, который затем будет сохранен в базе данных и, следовательно, отражен в моем пользовательском объекте. Я думал, что встроенные классы будут делать это автоматически, но я, должно быть, ошибаюсь
5. Spring не генерирует пустые поля существующих объектов. Он управляет объектами, сохраненными из приложения