java – JPA / Hibernate Embedded id

I want to do something like that:

>An object, reportingfile, can be a logrequest or logreport file (both have the same structure) > an object report contains a logrequest and a list of logreports with dates

I try to set an embeddedid, which will be a property of logrequest This is my problem I didn't get to mannage embedded ID( http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity -mapping-identifier)

If you have a clue about what I should do:)

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 example, I have the following errors:

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

Solution

OK, we'll see

You have an @ associationoverride annotation. Its API says:

and

In your question, I have neither seen @ manytoone nor @ onotooone So, you have a problem

But I saw the following logs in stacktrace

You have a composite primary key defined by the @ embeddedid annotation, which has two properties (filename and xmlcontent)

Now, let's take a look at 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 contains only one attribute, while your composite primary key contains two attributes Both must match It explains why you see the good news

Your correct mapping should look 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;

More: I don't know if your target database supports CLOB as the primary key So remember it

Add to the original answer based on your reply

1 º first case (no @ 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;

   }

}

Remember the following: Hibernate does not allow you to define two properties that share the same column Therefore, I must define insertable = false and updatable = false in the filename attribute

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 case (using @ 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",updatable=false))
    private List<ReportingFile> reports;

    @Embeddable
    public static class ReportingFile implements Serializable {

        // You must set up insertable=false,updatable=false)
        private String fileName;

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

   }

}

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

Therefore, when you have @ collectionofelements that share a foreign key, it will not work as expected But you can do a solution

@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",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)
        private String fileName;

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

   }

}

Note that when used in classes you own, you can define the @ embeddable class as static

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>