java.lang.IllegalArgumentException:期待 IdClass 映射
Posted
技术标签:
【中文标题】java.lang.IllegalArgumentException:期待 IdClass 映射【英文标题】:java.lang.IllegalArgumentException: expecting IdClass mapping 【发布时间】:2016-12-01 12:15:58 【问题描述】:我已为我的实体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;
我使用org.springframework.orm.hibernate5.LocalSessionFactoryBean
类创建了一个SessionFactory
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
我做错了什么?请在此处提供您的意见
【问题讨论】:
如果删除@IdClass 会发生什么?它应该仍然可以正常工作 在删除 @IdClass 注释后,我也收到与上述相同的错误。 sessionFactory bean 创建中是否缺少任何映射? 我尝试了以下 5 个分析器。但我仍然遇到同样的错误。我正在使用 spring-4.3.2.RELEASE 和 hibernate-5.2.0.Final。 @Achaius - 在您的测试中,您试图让员工没有公司或团队。但是 Team 和 Company 是员工的 ID - 它们不能为空。除了公司和团队之外,您的 Employee 还有一个id
字段 - 您希望使用哪个作为 ID - company+team 或 id
字段?您需要详细说明您的设计/要求,然后我们可能会提供帮助。目前这种模式在很多地方都是错误的。不过,我设法克服了你提到的错误。
【参考方案1】:
在包含ID
的类中提及@IdClass
注释。
在this 发帖查看答案
【讨论】:
【参考方案2】: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;
...
【讨论】:
【参考方案3】:此链接可以帮助您 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;
【讨论】:
【参考方案4】:IdClass 不应该被定义为 Embeddable -
@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 和 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;
【讨论】:
我试过你的回答。但仍然得到与上述相同的错误。 如果是 OneToMany 映射或 IdClass 或配置,您可以尝试在上面缩小问题范围 感谢您的回复@farrellmr。我们需要在人和分支对象中进行多对一映射,而不是长/整数字段。请让我们知道是否有任何可能性。我也有同样的问题与我的应用程序... 老实说 Id 切换到 EmbeddedId - 原始类的问题在于它将 IdClass 与 EmbeddedId 混合,这造成了问题。根据我的经验,EmbeddedId 更易于使用【参考方案5】:复合键映射可以使用 IdClass 或 Embeddable 完成。如果您想使用 IdClass,您必须在 Employee 中使用 @Id 注释您的字段。
@IdClass(EmployeeId.class)
class Person
@Id
private Person person;
@Id
private Branch branch;
如果您想使用 Embedded 作为复合键,请从 Person 中删除 @IdClass(EmployeeId.class) 注释。您也不需要 Person 类中的人员和分支字段,因为它们是在您的 Embedded 类中定义的。
【讨论】:
我尝试了你的建议。又发现了同样的问题【参考方案6】:你的情况对应JPA 2.1 Specification的2.4.1 Primary Keys Corresponding to Derived Identities一章。
Employee
的身份源自Person
和Branch
的身份。您还没有显示它们中的任何一个的代码,所以我假设它们具有简单的主键。在这种关系中,Person
和 Branch
是“父实体”,Employee
是“依赖”实体。
Employee
的 ID 可以使用 IdClass
或 EmbeddedId
映射,不能同时使用两者。
参见2.4.1.1 派生身份规范一章。
如果你想使用IdClass
,那么:
id类的属性名和依赖实体类的id属性名必须对应如下:
实体类中的Id
属性和id类中对应的属性必须同名。...
如果实体中的Id
属性与父实体是多对一或一对一关系,则 id 类中的对应属性必须是 (...) 的类型Id
父实体的属性。
所以你的类看起来像这样(getter、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来表示其主键,则关系属性对应的嵌入id中的属性必须与父实体的主键类型相同,并且必须由@987654337指定@注解应用于关系属性。必须使用
MapsId
注解的value
元素来指定关系属性对应的嵌入id 内的属性名称。
代码如下所示:
@Entity
public class Employee
@EmbeddedId
private EmployeeId id;
@ManyToOne
@MapsId("personId") // Corresponds to the name of EmployeeId.personId
private Person person;
@ManyToOne
@MapsId("branchId") // Corresponds to the name of EmployeeId.branchId
private Branch branch;
@Embeddable
public class EmployeeId
private Long personId; // Corresponds to the type of Person ID
private Long branchId; // Corresponds to the type of Branch ID
【讨论】:
谢谢@Adam Michalik 尝试了你的答案,但仍然遇到同样的错误。任何其他建议【参考方案7】:改为:
@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;
【讨论】:
我试过这个答案。但观察到与上述相同的错误以上是关于java.lang.IllegalArgumentException:期待 IdClass 映射的主要内容,如果未能解决你的问题,请参考以下文章