JPA/Hibernate Embedded id
Well, let's see
You have a @AssociationOverride annotation which its API says:
This annotation is used to override a many-to-one or one-to-one mapping of property or field for an entity relationship.
And
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
I have not seen neither @ManyToOne nor @OnoToOne in your question. So, There is something wrong with your question.
But i have seen the following log in your StackTrace
A Foreign key refering Reporting from Reporting has the wrong number of column. should be 2
You have a Compound primary key defined by a @EmbeddedId annotation which has two properties (fileName and xmlContent)
Now, let's see your @CollectionOfElements
@CollectionOfElements(fetch=FetchType.EAGER)
@JoinTable(name="t_reports",
// Your mistake goes here
joinColumns=@JoinColumn(name="log_report"))
@Fetch(FetchMode.SELECT)
private List<ReportingFile> reports;
Its Foreign key just contains one property whereas your Compound primary key contains two properties. Both must match. It explains why you see this nice message
A Foreign key refering Reporting from Reporting has the wrong number of column. should be 2
Your right mapping should looks like this
@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;
And more: i do not know whether your target database supports a Clob as primary key. So keep it in mind.
Added to original answer according to your reply
1º First scenario (without @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;
}
}
Keep in mind the following: Hibernate does not allow you define two properties where both share the same column. Because of that, i have to define insertable=false, updatable=false in fileName property.
And when i do the following
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
2º First scenario (with @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",
joinColumns=@JoinColumn(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;
}
}
And when i do the following
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 will complain
repeated column in mapping for collection: reports column: file_name
So, when you have a @CollectionOfElements which shares a foreign key, it will not work as expected. But you can do a workaround
@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",
joinColumns=@JoinColumn(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;
}
}
Notice you can define a @Embeddable class as static when using inside your owning class.
RoD
Updated on July 09, 2022Comments
-
RoD almost 2 years
I would like to do something like that:
- An object ReportingFile that can be a LogRequest or a LogReport file. ( both got the same structure)
- An object Reporting containing for one logRequest, a list of logReport with a date.
I tryed to set an EmbededId, that would be an attribute of the logRequest. And that's the problem i got. I don't arrive to mannage embedded id. ( http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-mapping-identifier )
If you have a clue on how i should do it :)
An example (not working) would be:
@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; [...] }
In this sample, i have a the following error:
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