在 OneToMany 和 ManyToMany 映射中获取 StackOverflow
Getting StackOverflow in OneToMany and ManyToMany mappings
当我尝试执行以下代码时,出现 Whosebug 异常
@Test
public void testMappings() {
EntityManager em = factory.createEntityManager();
Query q = em.createQuery("select f from Student f");
System.out.println(q.getResultList());
em.close();
}
我有三个实体(Student、Course、CourseRegistration),如下所示
例外如下
java.lang.WhosebugError
at org.jboss.logging.Log4jLogger.doLog(Log4jLogger.java:40)
at org.jboss.logging.Logger.debug(Logger.java:385)
at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:109)
at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:94)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:181)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:160)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.prepareQueryStatement(AbstractLoadPlanBasedLoader.java:257)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:201)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:137)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:100)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:693)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:92)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1933)
at org.hibernate.collection.internal.AbstractPersistentCollection.doWork(AbstractPersistentCollection.java:558)
谁能告诉我哪里错了
完整的源代码在 https://github.com/alexman31/jpatest/
中可用
更新 1
根据 @Anthony 和 @Nonika 的建议,我删除了所有的 lombok 注释并生成了显式的 setter/getter,toString ,等于和哈希码。但我仍然遇到同样的异常。
Student.java
@Entity
@Table(name = "student")
public class Student {
@Id
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@ManyToMany
@JoinTable(name = "course_registration", joinColumns = @JoinColumn(name = "student_id"), inverseJoinColumns = @JoinColumn(name = "course_id"))
private Set<Course> likedCourses;
@OneToMany(mappedBy = "student")
private Set<CourseRegistration> registrations;
// additional properties
public Student() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
if (getId() != null ? !getId().equals(student.getId()) : student.getId() != null) return false;
if (getName() != null ? !getName().equals(student.getName()) : student.getName() != null) return false;
if (getLikedCourses() != null ? !getLikedCourses().equals(student.getLikedCourses()) : student.getLikedCourses() != null)
return false;
return getRegistrations() != null ? getRegistrations().equals(student.getRegistrations()) : student.getRegistrations() == null;
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
result = 31 * result + (getLikedCourses() != null ? getLikedCourses().hashCode() : 0);
result = 31 * result + (getRegistrations() != null ? getRegistrations().hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", likedCourses=" + likedCourses +
", registrations=" + registrations +
'}';
}
public Long getId() {
return id;
}
public Set<Course> getLikedCourses() {
return likedCourses;
}
public Set<CourseRegistration> getRegistrations() {
return registrations;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setLikedCourses(Set<Course> likedCourses) {
this.likedCourses = likedCourses;
}
public void setRegistrations(Set<CourseRegistration> registrations) {
this.registrations = registrations;
}
}
Course.java
@Entity
@Table(name = "course")
public class Course {
@Id
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@ManyToMany(mappedBy = "likedCourses")
private Set<Student> likes;
@OneToMany(mappedBy = "course")
private Set<CourseRegistration> registrations;
// additional properties
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Course)) return false;
Course course = (Course) o;
if (getId() != null ? !getId().equals(course.getId()) : course.getId() != null) return false;
if (getName() != null ? !getName().equals(course.getName()) : course.getName() != null) return false;
if (getLikes() != null ? !getLikes().equals(course.getLikes()) : course.getLikes() != null) return false;
return getRegistrations() != null ? getRegistrations().equals(course.getRegistrations()) : course.getRegistrations() == null;
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
result = 31 * result + (getLikes() != null ? getLikes().hashCode() : 0);
result = 31 * result + (getRegistrations() != null ? getRegistrations().hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Course{" +
"id=" + id +
", name='" + name + '\'' +
", likes=" + likes +
", registrations=" + registrations +
'}';
}
public Course() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getLikes() {
return likes;
}
public void setLikes(Set<Student> likes) {
this.likes = likes;
}
public void setRegistrations(Set<CourseRegistration> registrations) {
this.registrations = registrations;
}
public Set<CourseRegistration> getRegistrations() {
return registrations;
}
}
CourseRegistration.java
@Entity
@Table(name = "course_registration")
public class CourseRegistration {
@Id
@Column(name = "id")
private Long id;
@ManyToOne
@JoinColumn(name = "student_id")
private Student student;
@ManyToOne
@JoinColumn(name = "course_id")
private Course course;
public CourseRegistration() {
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CourseRegistration)) return false;
CourseRegistration that = (CourseRegistration) o;
if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
if (getStudent() != null ? !getStudent().equals(that.getStudent()) : that.getStudent() != null) return false;
return getCourse() != null ? getCourse().equals(that.getCourse()) : that.getCourse() == null;
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getStudent() != null ? getStudent().hashCode() : 0);
result = 31 * result + (getCourse() != null ? getCourse().hashCode() : 0);
return result;
}
@Override
public String toString() {
return "CourseRegistration{" +
"id=" + id +
", student=" + student +
", course=" + course +
'}';
}
}
我已经构建了你的代码,发现这个问题是由于 lombok 生成的 hashCode()/equeals()
和 toString()
方法
at model.Student.hashCode(Student.java:13)
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
...
...
...
at model.Course.hashCode(Course.java:13)
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
我已经删除了所有 lombok 注释(将评分字段添加到数据库中),结果是:
[Student{id=123, name='Manu', likedCourses=[Course{id=224, name='Course2'}, Course{id=223, name='Course1'}], registrations=[CourseRegistration{id=1, rating=1}, CourseRegistration{id=2, rating=1}]}, Student{id=124, name='Susan', likedCourses=[Course{id=223, name='Course1'}], registrations=[CourseRegistration{id=3, rating=1}]}, Student{id=125, name='Jacob', likedCourses=[Course{id=224, name='Course2'}, Course{id=223, name='Course1'}], registrations=[CourseRegistration{id=4, rating=1}, CourseRegistration{id=5, rating=1}]}, Student{id=126, name='Mathew', likedCourses=[Course{id=224, name='Course2'}, Course{id=223, name='Course1'}, Course{id=226, name='Course4'}], registrations=[CourseRegistration{id=6, rating=1}, CourseRegistration{id=8, rating=1}, CourseRegistration{id=7, rating=1}]}, Student{id=127, name='Sunny', likedCourses=[], registrations=[]}]
您可以查看已编译的 类 实体,我的意思是那些 equals() 和 hashcode() 和 toString() lombok 为您生成的方法。因此,您尝试对 student:
调用 toString()
// Student
public String toString() {
return "Student(id=" + this.getId() + ", name=" + this.getName() + ", likedCourses=" + this.getLikedCourses() + ", registrations=" + this.getRegistrations() + ")";
}
// Course
public String toString() {
return "Course(id=" + this.getId() + ", name=" + this.getName() + ", likes=" + this.getLikes() + ", registrations=" + this.getRegistrations() + ")";
}
// CourseRegistration
public String toString() {
return "CourseRegistration(id=" + this.getId() + ", student=" + this.getStudent() + ", course=" + this.getCourse() + ", rating=" + this.getRating() + ")";
}
这将导致递归调用 toString 方法。
您可以将@ToString 与exclude 属性一起使用并显式实现equals 和hashcode,而不是使用@Data 和@EqualsAndHashCode 注释。
当我尝试执行以下代码时,出现 Whosebug 异常
@Test
public void testMappings() {
EntityManager em = factory.createEntityManager();
Query q = em.createQuery("select f from Student f");
System.out.println(q.getResultList());
em.close();
}
我有三个实体(Student、Course、CourseRegistration),如下所示
例外如下
java.lang.WhosebugError
at org.jboss.logging.Log4jLogger.doLog(Log4jLogger.java:40)
at org.jboss.logging.Logger.debug(Logger.java:385)
at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:109)
at org.hibernate.engine.jdbc.spi.SqlStatementLogger.logStatement(SqlStatementLogger.java:94)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:181)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:160)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.prepareQueryStatement(AbstractLoadPlanBasedLoader.java:257)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:201)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:137)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:102)
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:100)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:693)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:92)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1933)
at org.hibernate.collection.internal.AbstractPersistentCollection.doWork(AbstractPersistentCollection.java:558)
谁能告诉我哪里错了
完整的源代码在 https://github.com/alexman31/jpatest/
中可用更新 1
根据 @Anthony 和 @Nonika 的建议,我删除了所有的 lombok 注释并生成了显式的 setter/getter,toString ,等于和哈希码。但我仍然遇到同样的异常。
Student.java
@Entity
@Table(name = "student")
public class Student {
@Id
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@ManyToMany
@JoinTable(name = "course_registration", joinColumns = @JoinColumn(name = "student_id"), inverseJoinColumns = @JoinColumn(name = "course_id"))
private Set<Course> likedCourses;
@OneToMany(mappedBy = "student")
private Set<CourseRegistration> registrations;
// additional properties
public Student() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
if (getId() != null ? !getId().equals(student.getId()) : student.getId() != null) return false;
if (getName() != null ? !getName().equals(student.getName()) : student.getName() != null) return false;
if (getLikedCourses() != null ? !getLikedCourses().equals(student.getLikedCourses()) : student.getLikedCourses() != null)
return false;
return getRegistrations() != null ? getRegistrations().equals(student.getRegistrations()) : student.getRegistrations() == null;
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
result = 31 * result + (getLikedCourses() != null ? getLikedCourses().hashCode() : 0);
result = 31 * result + (getRegistrations() != null ? getRegistrations().hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", likedCourses=" + likedCourses +
", registrations=" + registrations +
'}';
}
public Long getId() {
return id;
}
public Set<Course> getLikedCourses() {
return likedCourses;
}
public Set<CourseRegistration> getRegistrations() {
return registrations;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setLikedCourses(Set<Course> likedCourses) {
this.likedCourses = likedCourses;
}
public void setRegistrations(Set<CourseRegistration> registrations) {
this.registrations = registrations;
}
}
Course.java
@Entity
@Table(name = "course")
public class Course {
@Id
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name;
@ManyToMany(mappedBy = "likedCourses")
private Set<Student> likes;
@OneToMany(mappedBy = "course")
private Set<CourseRegistration> registrations;
// additional properties
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Course)) return false;
Course course = (Course) o;
if (getId() != null ? !getId().equals(course.getId()) : course.getId() != null) return false;
if (getName() != null ? !getName().equals(course.getName()) : course.getName() != null) return false;
if (getLikes() != null ? !getLikes().equals(course.getLikes()) : course.getLikes() != null) return false;
return getRegistrations() != null ? getRegistrations().equals(course.getRegistrations()) : course.getRegistrations() == null;
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
result = 31 * result + (getLikes() != null ? getLikes().hashCode() : 0);
result = 31 * result + (getRegistrations() != null ? getRegistrations().hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Course{" +
"id=" + id +
", name='" + name + '\'' +
", likes=" + likes +
", registrations=" + registrations +
'}';
}
public Course() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getLikes() {
return likes;
}
public void setLikes(Set<Student> likes) {
this.likes = likes;
}
public void setRegistrations(Set<CourseRegistration> registrations) {
this.registrations = registrations;
}
public Set<CourseRegistration> getRegistrations() {
return registrations;
}
}
CourseRegistration.java
@Entity
@Table(name = "course_registration")
public class CourseRegistration {
@Id
@Column(name = "id")
private Long id;
@ManyToOne
@JoinColumn(name = "student_id")
private Student student;
@ManyToOne
@JoinColumn(name = "course_id")
private Course course;
public CourseRegistration() {
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CourseRegistration)) return false;
CourseRegistration that = (CourseRegistration) o;
if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
if (getStudent() != null ? !getStudent().equals(that.getStudent()) : that.getStudent() != null) return false;
return getCourse() != null ? getCourse().equals(that.getCourse()) : that.getCourse() == null;
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getStudent() != null ? getStudent().hashCode() : 0);
result = 31 * result + (getCourse() != null ? getCourse().hashCode() : 0);
return result;
}
@Override
public String toString() {
return "CourseRegistration{" +
"id=" + id +
", student=" + student +
", course=" + course +
'}';
}
}
我已经构建了你的代码,发现这个问题是由于 lombok 生成的 hashCode()/equeals()
和 toString()
方法
at model.Student.hashCode(Student.java:13)
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)
...
...
...
at model.Course.hashCode(Course.java:13)
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at java.util.HashSet.add(HashSet.java:220)
我已经删除了所有 lombok 注释(将评分字段添加到数据库中),结果是:
[Student{id=123, name='Manu', likedCourses=[Course{id=224, name='Course2'}, Course{id=223, name='Course1'}], registrations=[CourseRegistration{id=1, rating=1}, CourseRegistration{id=2, rating=1}]}, Student{id=124, name='Susan', likedCourses=[Course{id=223, name='Course1'}], registrations=[CourseRegistration{id=3, rating=1}]}, Student{id=125, name='Jacob', likedCourses=[Course{id=224, name='Course2'}, Course{id=223, name='Course1'}], registrations=[CourseRegistration{id=4, rating=1}, CourseRegistration{id=5, rating=1}]}, Student{id=126, name='Mathew', likedCourses=[Course{id=224, name='Course2'}, Course{id=223, name='Course1'}, Course{id=226, name='Course4'}], registrations=[CourseRegistration{id=6, rating=1}, CourseRegistration{id=8, rating=1}, CourseRegistration{id=7, rating=1}]}, Student{id=127, name='Sunny', likedCourses=[], registrations=[]}]
您可以查看已编译的 类 实体,我的意思是那些 equals() 和 hashcode() 和 toString() lombok 为您生成的方法。因此,您尝试对 student:
调用 toString()// Student
public String toString() {
return "Student(id=" + this.getId() + ", name=" + this.getName() + ", likedCourses=" + this.getLikedCourses() + ", registrations=" + this.getRegistrations() + ")";
}
// Course
public String toString() {
return "Course(id=" + this.getId() + ", name=" + this.getName() + ", likes=" + this.getLikes() + ", registrations=" + this.getRegistrations() + ")";
}
// CourseRegistration
public String toString() {
return "CourseRegistration(id=" + this.getId() + ", student=" + this.getStudent() + ", course=" + this.getCourse() + ", rating=" + this.getRating() + ")";
}
这将导致递归调用 toString 方法。
您可以将@ToString 与exclude 属性一起使用并显式实现equals 和hashcode,而不是使用@Data 和@EqualsAndHashCode 注释。