我已为我的实体Employee
配置了复合主键,如下所示
Employee.java:
@Entity
@Table(name="employee")
@Proxy(lazy=false)
@IdClass(EmployeeId.class)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private EmployeeId employeeId;
private Person person;
private Branch branch;
private boolean isActive;
public Employee() {
}
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name="person", column = @Column(name="person_id")),
@AttributeOverride(name="branch", column = @Column(name="branch_id"))})
public EmployeeId getEmployeeId() {
return employeeId;
}
public void setEmployeeId(EmployeeId employeeId) {
this.employeeId = employeeId;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="person_id")
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="branch_id")
public Branch getBranch() {
return branch;
}
public void setBranch(Branch branch) {
this.branch = branch;
}
@Column(name="is_active")
public boolean getIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
}
EmployeeId.java:
@Embeddable
public class EmployeeId implements Serializable {
private static final long serialVersionUID = 1L;
private Person person;
private Branch branch;
public EmployeeId() {
}
public EmployeeId(Person argPerson, Branch argbranch) {
this.person = argPerson;
this.branch = argbranch;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="person_id", insertable=false, updatable=false)
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="branch_id", insertable=false, updatable=false)
public Branch getBranch() {
return branch;
}
public void setBranch(Branch branch) {
this.branch = branch;
}
}
我使用类SessionFactory
创建了一个org.springframework.orm.hibernate5.LocalSessionFactoryBean
bean,并将所有hbm.xml
映射为MappingLocations
。
我的代码抛出以下错误:
Caused by: java.lang.IllegalArgumentException: expecting IdClass mapping
at org.hibernate.metamodel.internal.AttributeFactory$3.resolveMember(AttributeFactory.java:971)
at org.hibernate.metamodel.internal.AttributeFactory$5.resolveMember(AttributeFactory.java:1029)
at org.hibernate.metamodel.internal.AttributeFactory.determineAttributeMetadata(AttributeFactory.java:451)
at org.hibernate.metamodel.internal.AttributeFactory.buildIdAttribute(AttributeFactory.java:128)
at org.hibernate.metamodel.internal.MetadataContext.buildIdClassAttributes(MetadataContext.java:337)
at org.hibernate.metamodel.internal.MetadataContext.applyIdMetadata(MetadataContext.java:269)
at org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:190)
at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:219)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:296)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:476)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:707)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:723)
at org.springframework.orm.hibernate5.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:504)
at org.springframework.orm.hibernate5.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:488)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFac
如何避免此错误?我使用的是spring-orm-4.3.1-RELEASE
和hibernate-core-5.2.0.Final
。
更新
我创建了一个示例项目,运行时出现以下错误...
Caused by: org.hibernate.AnnotationException: Property of @IdClass not found in entity sample.domain.Employee: employee
参考代码:https://www.dropbox.com/s/axr8l01iqh0qr29/idclass-using-hibernate5.tar.gz?dl=0
我做错了什么?请在此提供您的意见
答案 0 :(得分:3)
复合键映射可以使用IdClass或Embeddable完成。如果要使用IdClass,则必须使用@Id在Employee中注释您的字段。
@IdClass(EmployeeId.class)
class Person{
@Id
private Person person;
@Id
private Branch branch;
}
如果要将Embedded用作复合键,请从Person中删除@IdClass(EmployeeId.class)注释。您也不需要Person类中的person和branch字段,因为它们是在Embedded类中定义的。
答案 1 :(得分:2)
您的情况对应于JPA 2.1 Specification的 2.4.1对应于派生身份的主键一章。
Employee
的身份来自Person
和Branch
的身份。你还没有显示其中任何一个的代码,所以我假设他们有简单的主键。在该关系中,Person
和Branch
是“父实体”,Employee
是“依赖”实体。
Employee
的ID可以使用IdClass
或EmbeddedId
映射,而不是同时使用。{/ p>
参见 2.4.1.1派生身份规范章节。
如果您想使用IdClass
,那么:
id类的属性名称和依赖实体类的Id属性必须如下对应:
- 实体类中的
Id
属性和id类中的相应属性必须具有相同的名称。...
- 如果实体中的
Id
属性是与父实体的多对一或一对一关系,则id类中的对应属性必须是(...)类型父实体的Id
属性。
所以你的类看起来像这样(getters,setter,多余的注释等省略)
@Entity
@IdClass(EmployeeId.class)
public class Employee {
@Id
@ManyToOne
private Person person;
@Id
@ManyToOne
private Branch branch;
}
public class EmployeeId {
private Long person; // Corresponds to the type of Person ID, name matches the name of Employee.person
private Long branch; // Corresponds to the type of Branch ID, name matches the name of Employee.branch
}
如果您使用EmbeddedId
,则:
如果从属实体使用嵌入式id表示其主键,则对应于relationship属性的嵌入式id中的属性必须与父实体的主键具有相同的类型,并且必须由{{指定1}}注释应用于关系属性。必须使用
MapsId
注释的value
元素来指定关系属性所对应的嵌入式ID中的属性名称。
代码看起来像这样:
MapsId
答案 2 :(得分:1)
更改为:
@Entity
@Table(name = "employee")
@Proxy(lazy = false)
@IdClass(EmployeeId.class)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private EmployeeId id;
private Person person;
private Branch branch;
private boolean isActive;
public Employee() {
}
@EmbeddedId
@AttributeOverrides({@AttributeOverride(name = "person", column = @Column(name = "person_id") ),
@AttributeOverride(name = "branch", column = @Column(name = "branch_id") )})
public EmployeeId getId() {
return id;
}
public void setId(EmployeeId id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "person_id")
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "branch_id")
public Branch getBranch() {
return branch;
}
public void setBranch(Branch branch) {
this.branch = branch;
}
@Column(name = "is_active")
public boolean getIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
}
答案 3 :(得分:1)
IdClass不应该被定义为可嵌入 -
@Entity
@Table(name="employee")
@IdClass(EmployeeId.class)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@ManyToOne
private Person person;
@Id
@ManyToOne
private Branch branch;
private boolean isActive;
public Employee() { }
//....
}
和 -
public class EmployeeId implements Serializable {
private static final long serialVersionUID = 1L;
private Person person;
private Branch branch;
public EmployeeId() {}
public EmployeeId(Person argPerson, Branch argbranch) {
this.person = argPerson;
this.branch = argbranch;
}
}
阅读您的评论 - 我是否可以建议您将Employee映射到person_id和branch_id,而不是JPA对象Person and Branch?这将让我们测试您的hbm配置是否正确。我还建议发布您的hbm配置,因为我认为此问题中缺少信息
因此该表类似于 -
@Entity
@Table(name="employee")
@IdClass(EmployeeId.class)
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private Long personId;
@Id
private Long branchId;
private boolean isActive;
public Employee() { }
//....
}
和 -
和 -
public class EmployeeId implements Serializable {
private static final long serialVersionUID = 1L;
private Long personId;
private Long branchId;
public EmployeeId() {}
public EmployeeId(Person argPerson, Branch argbranch) {
this.person = argPerson;
this.branch = argbranch;
}
}
答案 4 :(得分:0)
使用包含@IdClass
的类提及ID
注释。
在this帖子
答案 5 :(得分:0)
此链接可以帮助您 JPA - EmbeddedId with @ManytoOne
不支持嵌入式id类中定义的关系映射。然后你需要像这样更改embeddedId类
@Embeddable
public class EmployeeId implements Serializable {
private static final long serialVersionUID = 1L;
private Long personId;
private Long branchId;
public EmployeeId() {
}
public EmployeeId(Long argPerson, Long argbranch) {
this.personId = argPerson;
this.branchId = argbranch;
}
@Column(name = "person_id")
public Long getPersonId() {
return personId;
}
public void setPersonId(Long personId) {
this.personId = personId;
}
@Column(name = "branch_id")
public Long getBranchId() {
return branchId;
}
public void setBranchId(Long branchId) {
this.branchId = branchId;
}
}
答案 6 :(得分:0)
JPA复合主键
指定映射到实体的多个字段或属性的复合主键类。
主键类和字段中的字段或属性的名称 主要字段或实体的属性必须对应和 他们的类型必须相同。
答案就在这里。为您阅读说明。 enter link description here
(示例代码)
@Entity
@Table(name = "EMP_PROJECT")
@IdClass(ProjectAssignmentId.class)
public class ProjectAssignment {
@Id
@Column(name = "EMP_ID", insertable = false, updatable = false)
private int empId;
@Id
@Column(name = "PROJECT_ID", insertable = false, updatable = false)
private int projectId;
@ManyToOne
@JoinColumn(name = "EMP_ID")
Professor employee;
@ManyToOne
@JoinColumn(name = "PROJECT_ID")
Project project;
....
}
public class ProjectAssignmentId implements Serializable {
private int empId;
private int projectId;
...
}