我想在一个大清单中显示一些大型JPA(Hibernate)实体。为了获得合理的效果,并避免大量的'加入,我想为我的实体创建一些DTO。
实体有一个超类,所以我使用"表每个类继承映射" :
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
对于DTO,我使用了相同的JPA映射注释,排除了较大的字段。但这导致了一个例外:
org.hibernate.DuplicateMappingException: Duplicate table mapping
完整的堆栈跟踪:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:91)
at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:74)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:116)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:82)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:212)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:199)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:251)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:253)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:216)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:82)
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:60)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:67)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:162)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class org.nuytsm.HibernateDtoDuplicateTableMapping.springconfig.SpringOrmConfig: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: PU] Unable to build Hibernate SessionFactory
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1568)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
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.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:125)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:108)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:260)
at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:63)
at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:83)
... 31 more
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: PU] 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:341)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1627)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1564)
... 46 more
Caused by: org.hibernate.DuplicateMappingException: Duplicate table mapping SubClass1
at org.hibernate.cfg.Configuration$MappingsImpl.addDenormalizedTable(Configuration.java:2965)
at org.hibernate.cfg.annotations.TableBinder.buildAndFillTable(TableBinder.java:289)
at org.hibernate.cfg.annotations.TableBinder.buildAndFillTable(TableBinder.java:339)
at org.hibernate.cfg.annotations.EntityBinder.bindTable(EntityBinder.java:594)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:677)
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)
... 54 more
所以是的,异常说明了我想要实现的目标: - )。
实体:
超类:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class SuperClass {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "SID", nullable = false)
private Long id;
@Column(name = "NAME")
private String name;
Subclass1:
@Entity
@Table(name = "SubClass1")
public class SubClass1 extends SuperClass{
@Column(name="LONGSTRING")
@Lob
private String tooLongStringSoINeedDTO;
Subclass2:
@Entity
@Table(name = "SubClass2")
public class SubClass2 extends SuperClass{
@Column(name="BYTEARRAY")
@Lob
private byte[] someBigArray;
SuperclassDTO:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class SuperClassDto {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "SID", nullable = false)
private Long id;
@Column(name = "NAME")
private String name;
SubClass1DTO:
@Entity
@Table(name = "SubClass1")
public class SubClass1Dto extends SuperClassDto{
SubClass2DTO:
@Entity
@Table(name = "SubClass2")
public class SubClass2Dto extends SuperClassDto{
我煞费苦心地制作了一个最小的github maven project来说明这个问题,请随意尝试一下。您可以运行OrmTest junit测试来获取异常。
任何建议都会受到赞赏。 感谢
答案 0 :(得分:2)
您对两个不同的类使用相同的表名。这就是例外情况。
DTO-s不是实体。删除这些注释。我假设sudo /etc/init.d/apache2 restart
也不是实体。 (你有一个名为SuperClassDTO
的桌子吗?)
我认为你应该使用SUPER_CLASS_DTO
作为基本实体,@MappedSuperclass
作为子类。然后,DTO-s应该扩展超类,而不需要任何注释。
要了解差异,check this answer
修改强>
超类:
@Entity
Subclass1:
@MappedSuperclass
public class SuperClass {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "SID", nullable = false)
private Long id;
@Column(name = "NAME")
private String name;
Subclass2:
@Entity
@Table(name = "SubClass1")
public class SubClass1 extends SuperClass {
@Column(name="LONGSTRING")
@Lob
private String tooLongStringSoINeedDTO;
SuperclassDTO:
将其删除
SubClass1DTO:
@Entity
@Table(name = "SubClass2")
public class SubClass2 extends SuperClass {
@Column(name="BYTEARRAY")
@Lob
private byte[] someBigArray;
SubClass2DTO:
public class SubClass1Dto extends SuperClass {
答案 1 :(得分:2)
这可以通过 @ Embedded &来实现。 @ Embeddable 注释。
例如:
@Entity
public class Employee {
@Embedded
private EmployeeDetails details;
}
@Embeddable
public class EmployeeDetails {
}
您还可以在超类中创建一个仅包含必填字段的嵌入类。 因此消除了创建DTO的开销。
OR
如果您更喜欢使用 XML映射,那么
<!-- Hibernate Mapping 1 -->
<class name="com.SubClass1" table="SubClass1_Table">
<!-- Hibernate Mapping 2 -->
<class name="com.SubClass1" table="SubClass1_Table">