首页 > 解决方案 > Spring没有将复合键实体映射到数据库

问题描述

我有两个实体用户和焦点,我必须为其存储一个排名,以便用户可以对许多焦点进行排名,而一个焦点可能有很多用户。为了处理这个问题,我遵循了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) &&
                Objects.equals(focusID, ratingKey.focusID);
    }

    @Override
    public int hashCode() {
        return Objects.hash(userID, focusID);
    }
}

UserBaseRatings 表的 baseRating 的默认值为 1,这样如果用户对当前焦点没有评分,他们的评分应该是 1。我遇到了一个问题,如果用户没有评分,那么Rating 的集合是空的,而不是为每个存在的焦点评分 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;
    }
}

重点:

@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 添加到 Rating 实体:

@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=从更改noneupdate也没有任何区别。

标签: springspring-bootspring-mvcjpaspring-data-jpa

解决方案


如果您使用 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;
        }
    }    
}

推荐阅读