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-RELEASEhibernate-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 的身份源自PersonBranch 的身份。您还没有显示它们中的任何一个的代码,所以我假设它们具有简单的主键。在这种关系中,PersonBranch 是“父实体”,Employee 是“依赖”实体。

Employee 的 ID 可以使用 IdClassEmbeddedId 映射,不能同时使用两者。

参见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 映射的主要内容,如果未能解决你的问题,请参考以下文章

IllegalArgumentException:此 NavController 未知导航目的地 xxx