【问题标题】:java.lang.IllegalArgumentException: expecting IdClass mappingjava.lang.IllegalArgumentException:期待 IdClass 映射
【发布时间】: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 字段?您需要详细说明您的设计/要求,然后我们可能会提供帮助。目前这种模式在很多地方都是错误的。不过,我设法克服了你提到的错误。

标签: java spring-4 sessionfactory hibernate-5.x spring-orm


【解决方案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 Specification2.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;
        }
        
        }
        

        【讨论】:

        • 我试过这个答案。但观察到与上述相同的错误
        猜你喜欢
        • 1970-01-01
        • 2012-10-07
        • 1970-01-01
        • 1970-01-01
        • 2013-06-29
        • 1970-01-01
        • 1970-01-01
        • 2021-06-02
        • 1970-01-01
        相关资源
        最近更新 更多