[已解决] org.hibernate.AnnotationException:未为实体类指定标识符。
最近我在一个Hibernate项目上工作,我添加了几个实体Bean,当我运行时,出现了下面的异常堆栈追踪。
Initial SessionFactory creation failed.org.hibernate.AnnotationException: No identifier specified for entity: com.Olivia.hibernate.model.Address
org.hibernate.AnnotationException: No identifier specified for entity: com.Olivia.hibernate.model.Address
at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:277)
at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:224)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:775)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3788)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3742)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1410)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
at com.Olivia.hibernate.util.HibernateUtil.buildSessionFactory(HibernateUtil.java:22)
at com.Olivia.hibernate.util.HibernateUtil.getSessionFactory(HibernateUtil.java:34)
at com.Olivia.hibernate.main.HibernateExample.main(HibernateExample.java:15)
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.Olivia.hibernate.util.HibernateUtil.buildSessionFactory(HibernateUtil.java:29)
at com.Olivia.hibernate.util.HibernateUtil.getSessionFactory(HibernateUtil.java:34)
at com.Olivia.hibernate.main.HibernateExample.main(HibernateExample.java:15)
问题出现是因为我忘记在我的实体 bean 中指定主键,我的 bean 被定义为:Address.java。
package com.Olivia.hibernate.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
@Entity
@Table(name = "ADDRESS")
@Access(value=AccessType.FIELD)
public class Address {
@Column(name = "emp_id", unique = true, nullable = false)
@GeneratedValue(generator = "gen")
@GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
private long id;
@Column(name = "address_line1")
private String addressLine1;
@Column(name = "zipcode")
private String zipcode;
@Column(name = "city")
private String city;
@OneToOne
@PrimaryKeyJoinColumn
private Employee employee;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAddressLine1() {
return addressLine1;
}
public void setAddressLine1(String addressLine1) {
this.addressLine1 = addressLine1;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
@Override
public String toString() {
return "AddressLine1= " + addressLine1 + ", City=" + city
+ ", Zipcode=" + zipcode;
}
}
为了解决问题,我只需要使用@Id注解来注释主键字段。我将我的id字段声明修改为下面的内容,问题已经解决了。
@Id
@Column(name = "emp_id", unique = true, nullable = false)
@GeneratedValue(generator = "gen")
@GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
private long id;
这是一个简单的修复,但有一种情况会变得更加混乱。通常情况下,Hibernate会根据变量或Getter-Setter上使用的注解自动确定访问Bean属性的方式。然而,我们可以显式地为我们的实体Bean定义访问类型。有两种访问类型。
- 字段:在这种情况下,Hibernate将在变量上查找注解,例如我们在上面定义的Address类上的@Access(value=AccessType.FIELD)。
属性:在这种情况下,Hibernate将在getter-setter方法上查找注解,用于此的语法是@Access(value=AccessType.PROPERTY)。
如果注释未根据访问类型定义,那么我们也会遇到此异常。例如,如果访问类型是属性,而我们已经在bean变量上添加了所有注释,那么我们将会遇到此异常。下面给出了一个会抛出此异常的示例类。Employee.java
package com.Olivia.hibernate.model;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Cascade;
@Entity
@Table(name = "EMPLOYEE")
@Access(value=AccessType.FIELD)
public class Employee {
private long id;
private String name;
private double salary;
private Address address;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "emp_id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@OneToOne(mappedBy = "employee")
@Cascade(value = org.hibernate.annotations.CascadeType.ALL)
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Column(name = "emp_name")
public String getName() {
System.out.println("Employee getName called");
return name;
}
public void setName(String name) {
System.out.println("Employee setName called");
this.name = name;
}
@Column(name = "emp_salary")
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Id= " + id + ", Name= " + name + ", Salary= " + salary
+ ", {Address= " + address + "}";
}
}
请注意,所有的JPA注解都是与getter方法一起使用的,而访问类型被定义为Field,请将访问类型更改为property以解决此问题。