2010-03-15 5 views
6

Я хотел бы сделать что-то вроде этого:JPA/Hibernate врезанный идентификатор

  • Объектно ReportingFile, который может быть LogRequest или файл LogReport. (оба имеют ту же структуру)
  • Объект Сообщение, содержащее для одного logRequest, список logReport с датой.

Я попытался установить EmbededId, это будет атрибут logRequest. И это проблема, которую я получил. Я не прихожу к mannage встроенный id. (http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-mapping-identifier)

Если у вас есть подсказки о том, как я должен делать это :)

Пример (не работает) будет:

@Entity 
@AssociationOverride(name="logRequest.fileName", joinColumns = { @JoinColumn(name="log_request_file_name") }) 
public class Reporting { 

    @EmbeddedId 
    private ReportingFile logRequest; 

    @CollectionOfElements(fetch = FetchType.EAGER) 
    @JoinTable(name = "t_reports", schema="", joinColumns = {@JoinColumn(name = "log_report")}) 
    @Fetch(FetchMode.SELECT) 
    private List<ReportingFile> reports; 

    @Column(name="generated_date",nullable=true) 
    private Date generatedDate; 

    [...] 
} 

@Embeddable 
public class ReportingFile { 

    @Column(name="file_name",length=255) 
    private String fileName; 

    @Column(name="xml_content") 
    private Clob xmlContent; 

    [...] 
} 

В этом примере, у меня есть следующее сообщение об ошибке :

15.03.2010 16:37:59 [ERROR] org.springframework.web.context.ContextLoader  Context initialization failed 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0' defined in class path resource [config/persistenceContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [config/persistenceContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: test] Unable to configure EntityManagerFactory 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:480) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164) 
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:881) 
    at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:597) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:366) 
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:255) 
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199) 
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45) 
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3843) 
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4350) 
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045) 
    at org.apache.catalina.core.StandardHost.start(StandardHost.java:719) 
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045) 
    at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443) 
    at org.apache.catalina.core.StandardService.start(StandardService.java:516) 
    at org.apache.catalina.core.StandardServer.start(StandardServer.java:710) 
    at org.apache.catalina.startup.Catalina.start(Catalina.java:578) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288) 
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413) 
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [config/persistenceContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: test] Unable to configure EntityManagerFactory 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1337) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:308) 
    at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:270) 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:122) 
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:78) 
    at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:70) 
    at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:97) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1325) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473) 
    ... 29 more 
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: test] Unable to configure EntityManagerFactory 
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:265) 
    at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:125) 
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83) 
    at org.springframework.orm.jpa.LocalEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalEntityManagerFactoryBean.java:91) 
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:291) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334) 
    ... 46 more 
Caused by: org.hibernate.AnnotationException: A Foreign key refering Reporting from Reporting has the wrong number of column. should be 2 
    at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:272) 
    at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1319) 
    at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1158) 
    at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:600) 
    at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:541) 
    at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:43) 
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1140) 
    at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:319) 
    at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1125) 
    at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1226) 
    at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:159) 
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:854) 
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:191) 
    at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:253) 
    ... 52 more 

ответ

12

Ну, давайте посмотрим

у вас есть @AssociationOverride ап нотация, которая его API говорит:

This annotation is used to override a many-to-one or one-to-one mapping of property or field for an entity relationship.

И

It may be applied to an entity that extends a mapped superclass to override a many-to-one or one-to-one mapping defined by the mapped superclass

Я не видел ни @ManyToOne, ни @OnoToOne в вашем вопросе. Итак, с вашим вопросом что-то не так.

Но я видел следующий журнал в вашем StackTrace

A Foreign key refering Reporting from Reporting has the wrong number of column. should be 2

У вас есть соединение первичного ключа, определенная @EmbeddedId аннотации, который имеет два свойства (Filename и xmlContent)

Теперь, давайте посмотрим ваши @CollectionOfElements

@CollectionOfElements(fetch=FetchType.EAGER) 
@JoinTable(name="t_reports", 
    // Your mistake goes here 
    [email protected](name="log_report")) 
@Fetch(FetchMode.SELECT) 
private List<ReportingFile> reports; 

Его Внешний ключ содержит только одно свойство, тогда как ваш первичный ключ соединения содержит два свойства. Оба должны соответствовать. Это объясняет, почему вы видите это славного сообщение

A Foreign key refering Reporting from Reporting has the wrong number of column. should be 2

Вашего правильного отображение должно выглядеть следующим образом

@CollectionOfElements(fetch=FetchType.EAGER) 
@JoinTable(name="t_reports", 
    joinColumns={ 
     // The number of columns defined by our Compound primary key (2) 
     // must match the number of columns defined by its Foreign key (2) 
     @JoinColumn(name="file_name", referencedColumnName="file_name"), 
     @JoinColumn(name="xml_content", referencedColumnName="xml_content")}) 
@Fetch(FetchMode.SELECT) 
private List<ReportingFile> reports; 

И еще: я не знаю, поддерживает ли ваши целевую базу данных в CLOB в качестве первичного ключа. Поэтому имейте это в виду.

Добавлено в оригинальный ответ в соответствии с вашим ответом

Первый сценарий (без @CollectionOfElements)

@Entity 
public class Reporting { 

    // You said you just want a single fileName as primary key 
    @Id 
    @Column(name="file_name", nullable=false) 
    private String fileName; 

    // You said you still want to have the whole ReportingFile object 
    @Embedded 
    private ReportingFile reportingFile; 

    @Embeddable 
    public static class ReportingFile implements Serializable { 

     // You must set up insertable=false, updatable=false 
     @Column(name="file_name", insertable=false, updatable=false) 
     private String fileName; 

     @Column(name="xml_content") 
     private Clob xmlContent; 

    } 

} 

Имейте в виду следующее: Hibernate не позволяет определить два свойства, где оба имеют один и тот же столбец. Из-за этого мне нужно определить insertable = false, updatable = false в свойстве fileName.

И когда я делаю следующее

Reporting reporting = new Reporting(); 
reporting.setFileName("home.pdf"); 

ReportingFile reportingFile = new ReportingFile(); 
// It will not persisted because of insertable=false, updatable=false 
reportingFile.setFileName("home.pdf"); 
reportingFile.setXmlContent(someClobObject); 

session.save(reporting); // It works 

Первый сценарий (с @CollectionOfElements)

@Entity 
public class Reporting { 

    // You said you just want a single fileName as primary key 
    @Id 
    @Column(name="file_name", nullable=false) 
    private String fileName; 

    // You said you still want to have the whole ReportingFile object 
    @Embedded 
    private ReportingFile reportingFile; 

    @CollectionOfElements(fetch=FetchType.EAGER) 
    @JoinTable(
     name="t_reports", 
     [email protected](name="file_name", referencedColumnName="file_name", insertable=false, updatable=false)) 
    private List<ReportingFile> reports; 

    @Embeddable 
    public static class ReportingFile implements Serializable { 

     // You must set up insertable=false, updatable=false 
     @Column(name="file_name", insertable=false, updatable=false) 
     private String fileName; 

     @Column(name="xml_content") 
     private Clob xmlContent; 

    } 

}  

И когда я делаю следующее

Reporting reporting = new Reporting(); 
reporting.setFileName("home.pdf"); 

ReportingFile reportingFile = new ReportingFile(); 
// It will not persisted because of insertable=false, updatable=false 
reportingFile.setFileName("home.pdf"); 
reportingFile.setXmlContent(someClobObject); 

reporting.getReports().add(reportingFile); 

session.save(reporting); // It does not work 

Hibernateпожалуется

repeated column in mapping for collection: reports column: file_name

Так что, когда у вас есть @CollectionOfElements, который разделяет внешний ключ, он не будет работать, как ожидалось. Но вы можете сделать обходной путь

@Entity 
public class Reporting { 

    // You said you just want a single fileName as primary key 
    @Id 
    @Column(name="file_name", nullable=false) 
    private String fileName; 

    // You said you still want to have the whole ReportingFile object 
    @Embedded 
    private ReportingFile reportingFile; 

    // Your workaround goes here 
    @CollectionOfElements(fetch=FetchType.EAGER) 
    @JoinTable(
     name="t_reports", 
     [email protected](name="file_name", referencedColumnName="file_name")) 
    private List<Clob> xmlContents; 

    @Transient 
    public List<ReportingFile> getReports() { 
     List<ReportingFile> reports = new ArrayList<ReportingFile>(); 

     for(Clob xmlContent: getXmlContents()) 
      reports.add(new ReportingFile(getFileName(), xmlContent)); 

     return reports; 
    } 

    @Embeddable 
    public static class ReportingFile implements Serializable { 

     // required no-arg constructor 
     public ReportingFile() {} 

     public ReportingFile(String fileName, Clob xmlContent) { 
      this.fileName = fileName; 
      this.xmlContent = xmlContent; 
     } 

     // You must set up insertable=false, updatable=false 
     @Column(name="file_name", insertable=false, updatable=false) 
     private String fileName; 

     @Column(name="xml_content") 
     private Clob xmlContent; 

    } 

}  

Обратите внимание, вы можете определить @Embeddable класса как статические при использовании внутри имущего класса.

+0

Хорошо, спасибо! Дело в том, что я хотел иметь только fileName как первичный ключ, как вы сказали, чтобы избежать использования Clob в качестве первичного ключа. Но я не знаю, как указать EmbeddedId (и если это возможно), что он должен принимать только атрибут fileName в ReportingFile. Вот что я пытался сделать с @AssociationOverride. (с ошибкой, которую вы выделили) Вот почему в моем @CollectionOfElements я хотел иметь только один параметр. – RoD

+0

Итак, я изменил, что (добавление @OneToOne): \t @OneToOne \t @column (имя = "имя_файла", длина = 255) \t частная строка имя_файла; , чтобы соблюдать API. я следующее сообщение об ошибке: Вызванный: org.hibernate.AnnotationException: Незаконная попытка определить в @JoinColumn с ассоциацией mappedBy: logRequest.fileName Кажется, что это не так, чтобы выбрать только один из параметров для ПК , – RoD

+0

Извините, может быть, я не был очень ясен;) Мне нужно только имя файла (logRequest.fileName) как PK отчета, но я все еще хочу иметь весь объект ReportingFile (более частный отчет );). В том, что вы мне предлагаете, я потеряю «контент» моего файла. Если я добавил @Column (name = "xml_content") private Clob xmlContent; в класс Reporting, который вы дали, было бы хорошо, но я бы не использовал для этого объект ReportingFile (который является именно файломName + content). – RoD

Смежные вопросы