Java 带有 Hibernate 的 JPA - 如果实现复合键,则缺少列

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9828458/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 08:15:34  来源:igfitidea点击:

JPA with Hibernate - Missing Column if implementing composite keys

javamysqlspringhibernatejpa

提问by ziggy

JPA/Hibernate missing column

JPA/Hibernate 缺少列

I am using JPA with Hibernate as the provider. I had an entity class that had a single id column as the primary key. This worked fine but i now had to modify it so the primary key is a composite key comprised of two columns. To implement the composite key i used th example shown here how to create a composite primary key hibernate JPA?

我使用 JPA 和 Hibernate 作为提供程序。我有一个实体类,它有一个 id 列作为主键。这工作正常,但我现在必须修改它,因此主键是由两列组成的复合键。为了实现复合键,我使用了此处显示的示例如何创建复合主键休眠 JPA?

Here are the final classes:

以下是最后的课程:

The Primary Key

主键

@Embeddable
public class DocumentPK implements Serializable {


    private static final long serialVersionUID = 1L;

    @Basic(optional = false)
    @Column(name="P_ID")
    private String pId;

    @Basic(optional = false)
    @Column(name="P_NAME")
    private String pName;

    public DocumentPK() {
    }

    public DocumentPK(String pId, int pName) {
        this.pId = pId;
        this.pName = pName;
    }

    public String getPId() {
        return pId;
    }

    public void setPId(String pId) {
        this.pId = pId;
    }

    public String getPName() {
        return pName;
    }

    public void setPName(String pName) {
        this.pName = pName;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (pId != null ? pId.hashCode() : 0);
        hash += (int) pName;
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof DocumentPK)) {
            return false;
        }
        DocumentPK other = (DocumentPK) object;
        if ((this.pId == null && other.pId != null) || (this.pId != null && !this.pId.equals(other.pId))) {
            return false;
        }
        if (this.pName != other.pName) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "[ pId=" + pId + ", pName=" + pName + " ]";
    }    
}

After implementing the above primary key, i updated the Entity Class to 'embed' the primary key as shown below.

实现上述主键后,我更新了实体类以“嵌入”主键,如下所示。

@Entity
@Table(name="DOCUMENTS")

public class CustomerDocument implements Serializable{

    private static final long serialVersionUID = 6373600479711119252L;

    private     DocumentPK  id; 
    private     String  p_code;

    @EmbeddedId
    public DocumentPK getId() {
        return id;
    }

    public void setId(DocumentPK id) {
        this.id = id;
    }

    @Column(name="P_CODE")
    public String getPCode() {
        return p_code;
    }       
}

Now i have checked the 'DOCUMENTS' table and all columns are there. I even logged on to MySQL using the same user and i can see the table and the relevant columns. If i run the above it complains about not finding the P_ID column. Have i forgotten something somewhere?

现在我检查了“文档”表,所有列都在那里。我什至使用同一个用户登录到 MySQL,我可以看到表和相关列。如果我运行上面的它会抱怨没有找到 P_ID 列。我是不是忘记了某处?

18:30:45,279 ERROR [TestContextManager] Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@1d349e2] to prepare test instance [com.bt.msm.ds.dao.BatchNumberDaoTest@97d3f0]
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
    at org.junit.runners.ParentRunner.access
public class DocumentPK implements Serializable {

    private static final long serialVersionUID = 1L;

    private String pId;

    private String pName;
    /* The rest of the class, notice the missing annotations */
0(ParentRunner.java:41) at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:173) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:220) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0' defined in class path resource [my-spring-ds.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [my-spring-jpa.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: myPersistenceUnit] Unable to build EntityManagerFactory at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:294) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:728) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:449) at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:103) at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1) at org.springframework.test.context.support.DelegatingSmartContextLoader.loadContext(DelegatingSmartContextLoader.java:228) at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124) at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148) ... 24 more Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [msm-spring-jpa.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: myPersistenceUnit] Unable to build EntityManagerFactory at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) at org.springframework.beans.factory.support.AbstractBeanFactory.getObject(AbstractBeanFactory.java:294) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:400) at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:275) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:139) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:79) at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:70) at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:103) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1475) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1443) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) ... 36 more Caused by: javax.persistence.PersistenceException: [PersistenceUnit: myPersistenceUnit] Unable to build EntityManagerFactory at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:892) at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:73) at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:257) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452) ... 51 more Caused by: org.hibernate.HibernateException: Missing column: pId in mydb.documents at org.hibernate.mapping.Table.validateColumns(Table.java:277) at org.hibernate.cfg.Configuration.validateSchema(Configuration.java:1174) at org.hibernate.tool.hbm2ddl.SchemaValidator.validate(SchemaValidator.java:139) at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:387) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1385) at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954) at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:883) ... 56 more

采纳答案by esaj

I don't have anything to test this with right now, but try placing the @EmbeddedIdon the id-field instead of the method. If it doesn't work, try this instead:

我现在没有任何东西可以测试这个,但是尝试将@EmbeddedId放在 id 字段而不是方法上。如果它不起作用,请尝试以下操作:

DocumentPK:

文档PK:

@Entity
@Table(name="DOCUMENTS")
@IdClass(DocumentPK.class)
public class CustomerDocument implements Serializable{

    private static final long serialVersionUID = 6373600479711119252L;

    @Id
    @Column(name="P_ID", nullable=false)
    private String pId;

    @Id
    @Column(name="P_NAME", nullable=false)
    private String pName;

    private     String  p_code;

    /* Getters and setters */

CustomerDocument:

客户文件:

   public String getpId() {
      return pId;
   }

   public void setpId(String pId) {
      this.pId = pId;
   }

回答by baba.kabira

your getter and setter for P_ID are wrong

你的 P_ID 的 getter 和 setter 是错误的

public String getPId() {
    return pId;
}

public void setPId(String pId) {
    this.pId = pId;
}

should be

应该

@Embeddable
public class DocumentPK implements Serializable {
? ? 
? ? @Column(name="P_ID")
? ? private String pId;

? ? 
? ? @Column(name="P_NAME")
? ? private String pName;

? ? //get set………
}


@Entity
@Table(name="DOCUMENTS")
public class CustomerDocument implements Serializable{

? ? private static final long serialVersionUID = 6373600479711119252L;

    @Id
? ? private ? ? DocumentPK ?id; 
? ? private ? ? String ?p_code;//hoping this is not typo better pCode

? ?//get set …… ? 
}

Hope that helps

希望有帮助

Update:I have used composite keys and how I have configured in my code I have few suggestions.

更新:我使用了复合键以及如何在我的代码中配置我有一些建议。

@Column(name="P_ID")

Set up on similar grounds works for me.

在类似的理由上设置对我有用。

回答by Mikko Maunu

Shortly

不久

Add @Access(AccessType.FIELD) to the DocumentPK class (if your implementation supports JPA 2.0) or move annotations from fields to methods (works also with JPA 1.0 implementations).

将 @Access(AccessType.FIELD) 添加到 DocumentPK 类(如果您的实现支持 JPA 2.0)或将注释从字段移动到方法(也适用于 JPA 1.0 实现)。

In details

详情

正如您从日志中的错误消息中看到的:缺少列: pIdpId,所以这不是关于“找不到P_IDP_ID列”。以下是 DocumentPK 中的注释:

##代码##

does not have effect in your case because (from JPA 2.0 specification):

对您的情况没有影响,因为(来自 JPA 2.0 规范):

The access type of an embeddable class is determined by the access type of the entity class, mapped superclass, or embeddable class in which it is embedded (including as a member of an element collection) independent of whether the access type of the containing class has been explicitly specified or defaulted. A different access type for an embeddable class can be specified for that embeddable class by means of the Access annotation as described above.

可嵌入类的访问类型由其嵌入的实体类、映射超类或可嵌入类的访问类型决定(包括作为元素集合的成员),而与包含类的访问类型是否具有被明确指定或默认。可嵌入类的不同访问类型可以通过如上所述的访问注释为该可嵌入类指定。

Annotations in the fields of DocumentPK do not have effect, because it' access type is AccessType.PROPERTY. This access type is derived from CustomerDocument. CustomerDocument does use property access, because first mapping annotation found is for method (once again from JPA 2.0 specification):

DocumentPK 字段中的注释不起作用,因为它的访问类型是 AccessType.PROPERTY。此访问类型派生自 CustomerDocument。CustomerDocument 确实使用属性访问,因为找到的第一个映射注释是针对方法的(再次来自 JPA 2.0 规范):

The default access type of an entity hierarchy is determined by the placement of mapping annotations on the attributes of the entity classes and mapped superclasses of the entity hierarchy that do not explicitly specify an access type.

实体层次结构的默认访问类型由未明确指定访问类型的实体类和实体层次结构的映射超类的属性上的映射注释的位置确定。

To make it work you have to change access type in embedded class with @Access annotation or move annotations from fields to methods.

要使其工作,您必须使用 @Access 注释更改嵌入类中的访问类型,或者将注释从字段移动到方法。

Additionally: your code does not compile, because sometimes you treat pName as String and sometimes as int. Also in "Java-world" it is common practice to use camelCase names instead of underscores as word separators. Also you could consolidate names of fields and methods.

另外:您的代码无法编译,因为有时您将 pName 视为 String,有时将其视为 int。同样在“Java-world”中,通常的做法是使用驼峰命名而不是下划线作为单词分隔符。您也可以合并字段和方法的名称。