与其他两个实体相关的Hibernate实体在尝试查询数据库时会导致NPE

时间:2017-11-29 23:15:26

标签: java mysql hibernate entity-relationship

道歉,如果有明显的问题,我是Hibernate的新手。我花了最后3个小时来搜索谷歌,我很可能没有正确地表达我的问题。我想我可能会有一个循环引用,但我不确定。

我有3个实体。我想要实现的关系是:

  1. 机构可以有很多课程
  2. 机构可以是赞助商
  3. 课程可以有很多赞助商
  4. 赞助商可以有很多课程
  5. 我的单元测试创​​建这些实体,保存它们,然后查询它们以确保我可以阅读&正确地写入数据库并维护关系。

    1. 如果我只在课程中添加一个机构(BMC),一切都很好。
    2. 如果我只在课程中添加赞助商(BMC,HKU),一切都很好。
    3. 如果我将一个机构(BMC)和赞助商(BMC)添加到课程中,当我尝试重新学习课程时,我会得到一个空对象,最终导致NPE
    4. 我代表第三个实体CourseDetails中的多对多关系。最终,CourseDetails将具有多个多对多关系。但是,只有机构才能在多个地方使用。

      非常感谢任何帮助。

      **编辑**当我在Toad中查看时,我可以确认数据正在数据库中正确保存。课程表具有正确的institution_id,courseDetails_institution具有course_id和institution_id的正确映射

      机构

      @Entity
      @Table(name="institution")
      public class Institution {
          @Id
          @GeneratedValue(strategy = GenerationType.TABLE, generator="table-generator")
          @TableGenerator(name = "table-generator", pkColumnValue = "institution_id")
          @Column(name = "institution_id")
          private int id;
      
          @Column(name = "sponsor")
          private boolean sponsor;
      
          @ManyToMany(mappedBy = "sponsors", fetch = FetchType.EAGER)
          protected Set<CourseDetails> courseDetails = new HashSet<>();
      
          @OneToMany(mappedBy = "institution")
          @Cascade({CascadeType.SAVE_UPDATE})
          protected Set<Course> courses = new HashSet<>();
      
          protected Institution() {
              // no-op constructor for hibernate, cannot be private
          }
      
          public Institution(String name, String abbreviation) {
              super(name, abbreviation);
              this.sponsor = false;
          } 
      // Setters, getters, equals, hashcode omitted for brevity.
      

      课程

      @Entity
      @Table(name = "course")
      public class Course {
          @Id
          @GeneratedValue(strategy = GenerationType.TABLE, generator="table-generator")
          @TableGenerator(name = "table-generator", pkColumnValue = "course_id")
          @Column(name = "course_id")
          private int id;
      
          @ManyToOne
          private Institution institution;
      
          @ManyToMany(mappedBy = "courses", fetch = FetchType.EAGER)
          protected Set<CourseDetails> courseDetails = new HashSet<>();
      // Setters, getters, equals, hashcode omitted for brevity.
      

      CourseDetails

      @Entity
      @Table(name="courseDetails")
      public class CourseDetails {
          @Id
          @GeneratedValue(strategy = GenerationType.TABLE, generator = "table-generator")
          @TableGenerator(name = "table-generator", pkColumnValue = "courseDetails_id")
          @Column(name = "courseDetails_id")
          private int id;
      
          @ManyToMany(fetch = FetchType.LAZY)
          @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
          protected Set<Course> courses = new HashSet<>();
      
          @ManyToMany(fetch = FetchType.LAZY)
          @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
          protected Set<Institution> sponsors = new HashSet<>();
          // Setters, getters, equals, hashcode omitted for brevity.
      

      查询的相关方法

      public <T> List getAllEntities(final Class<T> clazz) {
          CriteriaBuilder builder = sessionFactory.getCriteriaBuilder();
          CriteriaQuery<T>  criteria = builder.createQuery(clazz);
          Root<T> root = criteria.from(clazz);
          criteria.select(root);
          final Session session = startTransaction();
          List<T> results = session.createQuery(criteria).getResultList();
          endTransaction(session);
          return results;
      }
      
      public Session startTransaction() {
          Session session = sessionFactory.openSession();
          session.beginTransaction();
          activeSessions.add(session);
          return session;
      }
      
      public void endTransaction(final Session session) {
          session.getTransaction().commit();
          session.close();
          activeSessions.remove(session);
      }
      

1 个答案:

答案 0 :(得分:0)

朱&#39;评论回答了我的问题。我需要让机构成为多对多关系,或者创建两个映射到同一个表的实体。这就是我最终做的事情:

<强> BaseInstitution

@Entity
@Table(name="institution")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorFormula(
        "CASE WHEN sponsor " +
        "THEN 'SPONSOR' " +
        "ELSE 'INSTITUTION' " +
        "END "
)
public class BaseInstitution {  
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="table-generator")
    @TableGenerator(name = "table-generator", pkColumnValue = "institution_id")
    @Column(name = "institution_id")
    private int id;

    @Column(name = "sponsor")
    private boolean sponsor = false;

<强>赞助

@Entity
@DiscriminatorValue("SPONSOR")
public class Sponsor extends BaseInstitution {  
    @ManyToMany(mappedBy = "sponsors", fetch = FetchType.EAGER)
    protected Set<CourseDetails> courseDetails = new HashSet<>();

<强>机构

@Entity
@DiscriminatorValue("INSTITUTION")
public class Institution extends BaseInstitution {
    @OneToMany(mappedBy = "institution")
    @Cascade({CascadeType.SAVE_UPDATE})
    protected Set<Course> courses = new HashSet<>();

<强>课程

@Entity
@Table(name = "course")
public class Course {  
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="table-generator")
    @TableGenerator(name = "table-generator", pkColumnValue = "course_id")
    @Column(name = "course_id")
    private int id;

    @ManyToOne
    @Cascade({CascadeType.SAVE_UPDATE})
    private Institution institution;

    @ManyToMany(mappedBy = "courses", fetch = FetchType.EAGER)
    protected Set<CourseDetails> courseDetails = new HashSet<>();

<强> CourseDetails

@Entity
@Table(name="courseDetails")
public class CourseDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "table-generator")
    @TableGenerator(name = "table-generator", pkColumnValue = "courseDetails_id")
    @Column(name = "courseDetails_id")
    private int id;

    @ManyToMany(fetch = FetchType.LAZY)
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    protected Set<Course> courses = new HashSet<>();

    @ManyToMany(fetch = FetchType.EAGER)
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
    protected Set<Sponsor> sponsors = new HashSet<>();