如何使用doSecondPass异常解决jpa和hibernate一对一注释

时间:2011-12-08 11:08:44

标签: java hibernate jpa

您好我正在编写使用jpa和Hibernate 3.2版本将数据插入两个表的简单代码。我的注意事项是将Employee详细信息保存在两个表中,即Employee包含employeeId,这是主键,手动分配指定值和员工地址使用@onetoOne annotions在Employee表中共享主键employeeId。我喜欢这样的类

@Entity
@Table(name = "employee", catalog = "test", uniqueConstraints = {})
public class Employee implements java.io.Serializable {

    // Fields

    private Integer employeeid;

    private String name;

    private Employeeaddress employeeaddress;
    // Constructors

    /** default constructor */
    public Employee() {
    }

    /** minimal constructor */
    public Employee(Integer employeeid) {
        this.employeeid = employeeid;
    }

    /** full constructor */
    public Employee(Integer employeeid, String name) {
        this.employeeid = employeeid;
        this.name = name;
    }

    // Property accessors
    @Id
    @Column(name = "EMPLOYEEID", unique = true, nullable = false, insertable = true, updatable = true)
    public Integer getEmployeeid() {
        return this.employeeid;
    }

    public void setEmployeeid(Integer employeeid) {
        this.employeeid = employeeid;
    }

    @Column(name = "NAME", unique = false, nullable = true, insertable = true, updatable = true, length = 45)
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToOne(mappedBy="employee")
    @PrimaryKeyJoinColumn
    public Employeeaddress getEmployeeaddress() {
        return employeeaddress;
    }

    public void setEmployeeaddress(Employeeaddress employeeaddress) {
        this.employeeaddress = employeeaddress;
    }
}


@Entity
@Table(name = "employeeaddress", catalog = "test", uniqueConstraints = {})
public class Employeeaddress implements java.io.Serializable {

    // Fields

    private Integer employeeid;

    private String address;

    private Employee employee;
    // Constructors

    /** default constructor */
    public Employeeaddress() {
    }

    /** minimal constructor */
    public Employeeaddress(Integer employeeid) {
        this.employeeid = employeeid;
    }

    /** full constructor */
    public Employeeaddress(Integer employeeid, String address) {
        this.employeeid = employeeid;
        this.address = address;
    }

    // Property accessors
    @Id
    @Column(name = "EMPLOYEEID", unique = true, nullable = false, insertable = true, updatable = true)
    public Integer getEmployeeid() {
        return this.employeeid;
    }

    public void setEmployeeid(Integer employeeid) {
        this.employeeid = employeeid;
    }

    @Column(name = "ADDRESS", unique = false, nullable = true, insertable = true, updatable = true, length = 45)
    public String getAddress() {
        return this.address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @OneToOne(mappedBy="employeeaddress")
    @PrimaryKeyJoinColumn
    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

}

我的主要课程是

public class EmployeeDao {
    public static void main(String[] args) {
        try{
        AnnotationConfiguration cfg = new AnnotationConfiguration();
        cfg.addAnnotatedClass(employeeforms.Employee.class);
        cfg.addAnnotatedClass(employeeforms.Employeeaddress.class);
        SessionFactory sessionFactory = cfg.buildSessionFactory();
        Session session =sessionFactory.openSession();
        Employee e = new Employee();
        e.setEmployeeid(100872);
        e.setName("sandeep");
        Employeeaddress ed = new Employeeaddress();     
        ed.setAddress("Hyderabad");
        e.setEmployeeaddress(ed);
        session.save(e);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

}

当我运行我的主课时,我得到以下异常

java.lang.NullPointerException
    at org.hibernate.cfg.OneToOneSecondPass.doSecondPass(OneToOneSecondPass.java:135)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1130)
    at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:296)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1286)
    at employeeDao.EmployeeDao.main(EmployeeDao.java:16)

我的桌子是

    CREATE TABLE  employee (
      EMPLOYEEID int(10) unsigned NOT NULL ,
      NAME varchar(45) default '',
      PRIMARY KEY  (EMPLOYEEID`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

    CREATE TABLE  employeeaddress (
      EMPLOYEEID int(10) unsigned NOT NULL default '0',
      ADDRESS varchar(45) default '',
      PRIMARY KEY  (EMPLOYEEID)
    ) ENGINE=InnoDB 
DEFAULT CHARSET=latin1;

2 个答案:

答案 0 :(得分:1)

你有(至少)三个问题。

第一个问题:你指定

@OneToOne(mappedBy="employee")
@PrimaryKeyJoinColumn

@OneToOne(mappedBy="employeeaddress")
@PrimaryKeyJoinColumn

这两个注释是矛盾的;如果设置了mappedBy,则意味着映射信息位于另一侧。只有一方应定义映射(@PrimaryKeyJoinColumn),另一方应设置mappedBy属性。

第二个问题:你指定

Employeeaddress ed = new Employeeaddress();     
ed.setAddress("Hyderabad");
e.setEmployeeaddress(ed);

应初始化协会的双方。因此代码应该这样做:

e.setEmployeeaddress(ed);
ed.setEmployee(e);

Hibernate使用mappedBy not 设置的一侧来知道是否存在关联。

第三个问题:

您保存员工,但不保存地址。并且员工之间没有级联设置。

答案 1 :(得分:0)

基于these hibernate 3.6 docs,您的映射应如下所示:

@Entity
@Table(name = "employee", catalog = "test", uniqueConstraints = {})
public class Employee implements java.io.Serializable {

    private Integer employeeid;
    private Employeeaddress employeeaddress;
    // other fields and constructors

    @Id
    @Column(name = "EMPLOYEEID", unique = true, nullable = false, insertable = true, updatable = true)
    public Integer getEmployeeid() {
        return this.employeeid;
    }

    public void setEmployeeid(Integer employeeid) {
        this.employeeid = employeeid;
    }


    @OneToOne(mappedBy="employee")
    public Employeeaddress getEmployeeaddress() {
        return employeeaddress;
    }

    public void setEmployeeaddress(Employeeaddress employeeaddress) {
        this.employeeaddress = employeeaddress;
    }
}


@Entity
@Table(name = "employeeaddress", catalog = "test", uniqueConstraints = {})
public class Employeeaddress implements java.io.Serializable {

    private Integer employeeid;
    private Employee employee;

    @Id
    @Column(name = "EMPLOYEEID", unique = true, nullable = false, insertable = true, updatable = true)
    public Integer getEmployeeid() {
        return this.employeeid;
    }
    // EDIT: private setter for employeeid, id is set by setEmployee() but hibernate needs a setter to initialize the instance on load
    private void setEmployeeid(Integer id) {
        this.employeeid = id;
    }


    @OneToOne
    @MapsId
    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

}

编辑: @MapsId注释是在JPA 2.0中引入的(我认为自3.5以来在hibernate中实现)。如果您使用的是未实现JPA 2.0规范的较旧的hibernate版本,则可以为这样的两个实体映射相同的id(类Employee保持不变):

@Entity
@Table(name = "employeeaddress", catalog = "test", uniqueConstraints = {})
public class Employeeaddress implements java.io.Serializable {

    private Integer employeeid;
    private Employee employee;

    @Id
    @GeneratedValue(generator = "anyName")
    @GenericGenerator(name = "anyName", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
    @Column(name = "EMPLOYEEID", unique = true, nullable = false, insertable = true, updatable = true)
    public Integer getEmployeeid() {
        return this.employeeid;
    }
    // EDIT: private setter for employeeid, id is set by setEmployee() but hibernate needs a setter to initialize the instance on load
    private void setEmployeeid(Integer id) {
        this.employeeid = id;
    }   

    @OneToOne
    @PrimaryKeyJoinColumn
    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

}

在保存关联的瞬态/分离Employeeaddress实例或将类Employee中的注释更改为级联保存之前,您还必须先保存瞬态/分离的Employee实例:

@OneToOne(mappedBy="employee", cascade = CascadeType.SAVE_UPDATE)
public Employeeaddress getEmployeeaddress() {
    return employeeaddress;
}