2015-04-26 52 views
3

我想爲一組嵌入式使用自定義集合類型。如何用Hibernate 4.3.8和Spring Boot使用基於Java的配置來實現這一點?Hibernate:如何使用@Embeddables的自定義集合?

我的嵌入式看起來像這樣

@Embeddable 
public class MyEmbeddable implements Entry<Object, Integer> { 
} 

,並且具有這樣的

@Entity 
public class MyOtherClass { 
    @ElementCollection(fetch = FetchType.EAGER) 
    private Set<MyEmbeddable> embeddables; 
} 

一套這種嵌入外觀的實體,我想實現這樣的

@Entity 
public class MyOtherClass { 
    @ElementCollection(fetch = FetchType.EAGER) 
    private MyCustomSet embeddables; 
} 

public class MyCustomSet extends HashSet<MyEmbeddable> { 

    //some custom methods... 

} 

我試着用UserCollectionType@CollectionType但沒有成功,沒有找到任何教程/例子。

MyCustomSet

public class MyCustomSet extends HashSet<MyEmbeddable> implements UserCollectionType { 

    @Override 
    public PersistentCollection instantiate(final SessionImplementor session, final CollectionPersister persister) throws HibernateException { 
     return new PersistentSet(); 
    } 

    @Override 
    public PersistentCollection wrap(final SessionImplementor session, final Object collection) { 
     return new PersistentSet(session, (Set) collection); 
    } 

    @Override 
    public Iterator<Ingredient> getElementsIterator(final Object collection) { 
     return ((Set<MyEmbeddable>) collection).iterator(); 
    } 

    @Override 
    public boolean contains(final Object collection, final Object entity) { 
     return ((Set<MyEmbeddable>) collection).contains(entity); 
    } 

    @Override 
    public Object indexOf(final Object collection, final Object entity) { 
     return null; 
    } 

    @Override 
    public Object replaceElements(final Object original, final Object target, final CollectionPersister persister, final Object owner, final Map copyCache, 
      final SessionImplementor session) throws HibernateException { 

     final Set originalSet = (Set) original; 
     final Set targetSet = (Set) target; 

     targetSet.clear(); 
     targetSet.addAll(originalSet); 

     return targetSet; 
    } 

    @Override 
    public Object instantiate(final int anticipatedSize) { 
     return new MyCustomSet(); 
    } 

} 

我與自定義實體設置

@Entity 
public class MyEntity { 


    @ElementCollection(fetch = FetchType.EAGER) 
    @CollectionType(type = "com.blubb.MyCustomSet") 
    private MyCustomSet custom; 

    public MyEntity() { 
    } 

    public MyEntity(final MyCustomSet custom) { 
     this.custom = custom; 
    } 


    public MyCustomSet getCustom() { 
     return this.custom; 
    } 

    public void setCustom(final MyCustomSet custom) { 
     this.custom = custom; 
    } 

} 

Throwns例外是

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) 
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:956) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:747) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480) 
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686) 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:320) 
    at org.springframework.boot.test.SpringApplicationContextLoader.loadContext(SpringApplicationContextLoader.java:100) 
    at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:68) 
    at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:86) 
    at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:72) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) 
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:212) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:200) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:259) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:261) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:219) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163) 
    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:459) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1239) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:855) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:845) 
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:398) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:844) 
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) 
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343) 
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1625) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562) 
    ... 39 common frames omitted 
Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: com.blubb.MyEntity.custom 
    at org.hibernate.cfg.annotations.CollectionBinder.getCollectionBinder(CollectionBinder.java:330) 
    at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1922) 
    at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:963) 
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:796) 
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3845) 
    at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3799) 
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1412) 
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846) 
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:852) 
    ... 47 common frames omitted 

回答

1

您不應覆蓋集合類型,而將它們作爲@ElementCollection關聯。 Hibernate使用自己的集合代理來檢查entity dirtiness並提供延遲初始化。

即使指定了HashSet<Entity>,Hibernate也會用PersistentSet替換類型。

UserCollectionType可用於實體關聯,但它可能不適用於可嵌入的集合。

如果你願意MyEmbeddable轉換爲一個實體,這是自定義集合會是什麼樣子:

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
@JoinColumn(name = "id") 
@CollectionTypeInfo(name = "package.MyCustomSet") 
public Set<MyEmbeddable> getMyEmbeddables() { 
    ... 
} 
+0

感謝。我不知道你的答案如何幫助我。我需要自定義集合類型,因爲我需要重寫並向我的自定義集合中添加一些方法。使用像HashSet這樣的Java集合對我來說不是一個解決方案。我猜爲此目的UserCollectionType存在,因爲它有一些將自定義集合類型轉換爲PersistentCollection的方法,所以Hibernate可以做它的代理/替換,但不幸的是,它不起作用。 – zersaegen

+0

查看我的更新回答 –

+0

好的謝謝。我預計它不適用於Embeddables。感謝您的解釋。我可能會使用此處解釋的組合方法(http://stackoverflow.com/a/3174394/1089459),然後:-( – zersaegen

相關問題