我正在尝试使用spring + JPA在实体之间实现单向多对多关系。
尝试几次更改休眠版本后,我不知道是什么原因
由以下原因引起:org.springframework.orm.jpa.JpaSystemException:通过持久性属性[com.uca.refactor2]的反射访问字段[private java.lang.Integer com.uca.refactor2.model.Achievement.id]时出错。 model.Achievement#id]:1;嵌套的异常是org.hibernate.property.access.spi.PropertyAccessException:通过对持久属性[com.uca.refactor2.model的反射]访问字段[private java.lang.Integer com.uca.refactor2.model.Achievement.id]时出错.Achievement#id]:1
User.java
@Entity
@Table(name="USER")
public class User implements Serializable {
private static final long serialVersionUID = 4402583037980335445L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String firstName;
private String lastName;
@Column(unique = true)
private String username;
private String password;
@Enumerated(EnumType.STRING)
private UserType userType;
@OneToMany(cascade=CascadeType.ALL, mappedBy="joinedUserAchievementId.user")
private List<JoinedUserAchievement> joinedUserAchievementList = new ArrayList<JoinedUserAchievement>();
public User() {}
public User(Integer id) {
this.id = id;
}
public User(String username, String firstName, String lastName,
String password, UserType userType) {
this.username = username;
this.firstName = firstName;
this.lastName = lastName;
this.password = password;
this.userType = userType;
}
public List<JoinedUserAchievement> getAllAchievement() {
return joinedUserAchievementList;
}
public void addAchievement(Achievement achievement) {
// Notice a JoinedUserAchievement object
Date dateOfAcquisition = new Date();
JoinedUserAchievement joinedUserAchievement = new JoinedUserAchievement(new JoinedUserAchievement.JoinedUserAchievementId(this, achievement),dateOfAcquisition );
joinedUserAchievement.setAchievementId(achievement.getId());
joinedUserAchievementList.add(joinedUserAchievement);
}
//set and gets
JoinedUserAchievement.java
@Entity
@Table(name="USER_ACHIEVEMENT")
public class JoinedUserAchievement {
public JoinedUserAchievement() {}
public JoinedUserAchievement(JoinedUserAchievementId joinedUserAchievementId, Date dateOfAcquisition) {
this.joinedUserAchievementId = joinedUserAchievementId;
this.dateOfAcquisition = dateOfAcquisition;
}
@ManyToOne(targetEntity = Achievement.class)
@JoinColumn(name="id", insertable=false, updatable=false)
private Integer achievementId;
private Date dateOfAcquisition;
public String getDate() {
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date date = dateOfAcquisition;
return dateFormat.format(date);
}
public Integer getAchievementId() {
return achievementId;
}
public void setAchievementId(Integer achievementId) {
this.achievementId = achievementId;
}
@EmbeddedId
private JoinedUserAchievementId joinedUserAchievementId;
// required because JoinedUserAchievments contains composite id
@Embeddable
public static class JoinedUserAchievementId implements Serializable {
/**
*
*/
private static final long serialVersionUID = -9180674903145773104L;
@ManyToOne
@JoinColumn(name="USER_ID")
private User user;
@ManyToOne
@JoinColumn(name="ACHIEVEMENT_ID")
private Achievement achievement;
// required no arg constructor
public JoinedUserAchievementId() {}
public JoinedUserAchievementId(User user, Achievement achievement) {
this.user = user;
this.achievement = achievement;
}
public JoinedUserAchievementId(Integer userId, Integer achievementId) {
this(new User(userId), new Achievement(achievementId));
}
public User getUser() {
return user;
}
public Achievement getAchievement() {
return achievement;
}
public void setUser(User user) {
this.user = user;
}
public void setAchievement(Achievement achievement) {
this.achievement = achievement;
}
@Override
public boolean equals(Object instance) {
if (instance == null)
return false;
if (!(instance instanceof JoinedUserAchievementId))
return false;
final JoinedUserAchievementId other = (JoinedUserAchievementId) instance;
if (!(user.getId().equals(other.getUser().getId())))
return false;
if (!(achievement.getId().equals(other.getAchievement().getId())))
return false;
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 47 * hash + (this.user != null ? this.user.hashCode() : 0);
hash = 47 * hash + (this.achievement != null ? this.achievement.hashCode() : 0);
return hash;
}
}
}
Achievement.java
@Entity
@Table(name="ACHIEVEMENT")
public class Achievement implements Serializable{
private static final long serialVersionUID = 7747630789725422177L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer points;
public Achievement() {
}
public Achievement(String name, Integer points) {
this.name = name;
this.points = points;
}
public Achievement(Integer id) {
this.id = id;
}
//set and gets
我也试图使这种关系成为双向,但是这种关系不起作用,所以我可能会遗漏一些东西
在此之前,我还没有Achivement对象而不是joinUserAchievement上的achivementId,它可以工作,但是我认为这不是我所需要的,我不需要总是获得每个成就对象,只需id就可以了。
答案 0 :(得分:1)
来自docs:
不支持在嵌入式id类中定义的关系映射
您应仅将id放在JoinedUserAchievementId
中,并将User
和Achievement
关联直接放在JoinedUserAchievement
中,如下所示:
public class JoinedUserAchievementId {
private Long userId;
private Long achievementId;
...
}
public class JoinedUserAchievement {
@EmbeddedId
private JoinedUserAchievementId joinedUserAchievementId;
@ManyToOne
@MapsId("userId")
@JoinColumn(name = "USER_ID")
private User user;
@ManyToOne(optional = false, fetch = LAZY)
@MapsId("achievementId")
@JoinColumn(name = "ACHIEVEMENT_ID")
private Achievement achievement;
//if you absolutely need to map the achievement_id column here as well
//note that it will already be mapped to joinedUserAchievementId.achievementId
@Column(name = "ACHIEVEMENT_ID", insertable=false, updatable=false)
private Long achievementId;
...
}
请记住将User.joinedUserAchievementList
映射更新为mappedBy="user"
。