JPA с Hibernate - отсутствует столбец при реализации составных ключей - PullRequest
1 голос
/ 22 марта 2012

JPA / Hibernate отсутствует столбец

Я использую JPA с Hibernate в качестве поставщика. У меня был класс сущности, у которого в качестве первичного ключа был один столбец идентификатора. Это работало нормально, но теперь мне пришлось изменить его, чтобы первичный ключ представлял собой составной ключ, состоящий из двух столбцов. Для реализации составного ключа я использовал приведенный здесь пример , как создать композитный первичный ключ в спящем режиме JPA?

Вот последние классы:

Первичный ключ

@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 + " ]";
    }    
}

После реализации вышеуказанного первичного ключа я обновил класс сущности, чтобы «встроить» первичный ключ, как показано ниже.

@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;
    }       
}

Теперь я проверил таблицу 'ДОКУМЕНТЫ', и все столбцы там. Я даже вошел в 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$1.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$000(ParentRunner.java:41)
    at org.junit.runners.ParentRunner$1.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$1.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$1.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

Ответы [ 3 ]

2 голосов
/ 22 марта 2012

У меня нет ничего, чтобы проверить это прямо сейчас, но попробуйте поместить @EmbeddedId в поле id вместо метода. Если это не сработает, попробуйте вместо этого:

DocumentPK:

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 */

CustomerDocument:

@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 */
1 голос
/ 24 марта 2012

Вскоре

Добавьте @Access (AccessType.FIELD) в класс DocumentPK (если ваша реализация поддерживает JPA 2.0) или переместите аннотации из полей в методы (работает также с реализациями JPA 1.0).

Подробнее

Как видно из сообщения об ошибке в журналах: отсутствует столбец: pId , поэтому речь не идет о "не обнаружении P_ID столбец ".Следующая аннотация в DocumentPK:
@Column(name="P_ID")

не действует в вашем случае, потому что (из спецификации JPA 2.0):

Тип доступа встраиваемого класса определяется доступомтип класса сущности, сопоставленного суперкласса или встраиваемого класса, в который он встроен (в том числе в качестве члена коллекции элементов), независимо от того, был ли тип доступа содержащего класса был явно указан или установлен по умолчанию.Другой тип доступа для встраиваемого класса может быть указан для этого встраиваемого класса посредством аннотации Access, как описано выше.

Аннотации в полях DocumentPK не действуют, потому что это «тип доступаэто AccessType.PROPERTY.Этот тип доступа является производным от CustomerDocument.CustomerDocument использует доступ к свойству, потому что первая найденная аннотация сопоставления относится к методу (еще раз из спецификации JPA 2.0):

Тип доступа по умолчанию для иерархии сущностей определяется размещением аннотаций сопоставления ватрибуты классов сущностей и сопоставленных суперклассов иерархии сущностей, которые явно не указывают тип доступа.

Чтобы это работало, вам нужно изменить тип доступа во встроенном классе с помощью аннотации @Access или переместить аннотациииз полей в методы.

Дополнительно: ваш код не компилируется, потому что иногда вы рассматриваете pName как String, а иногда как int.Также в «мире Java» обычной практикой является использование имен camelCase вместо подчеркивания в качестве разделителей слов.Также вы можете объединить имена полей и методов.

1 голос
/ 22 марта 2012

ваш получатель и установщик для P_ID неверны

   public String getpId() {
      return pId;
   }

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

должно быть

public String getPId() {
    return pId;
}

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

Надеюсь, что поможет

Обновление: У меняиспользованные составные ключи и как я настроил в своем коде, у меня есть несколько предложений.

@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 ……   
}

Настройка на аналогичных основаниях работает для меня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...