2011-11-14 100 views
1

我想設置實體繼承使用JPA註釋和抽象類。JPA實體繼承與抽象類 - ConstrainViolationException

我們的目標是讓DAO通過其擴展與基礎對象一起工作,以便通過使用不同的實體擴展,切入點和覆蓋而不必更改提供者和管理者,就可以對同一應用程序進行變異。

例如: 基本應用程序堆棧有一個使用抽象公司實體堅持延伸公司所有對象DAO提供商:

@Entity 
@Inheritance(strategy = InheritanceType.JOINED) 
public abstract class Company extends AbstractPersistable<Long> { 

    @Column(unique = true) 
    private String register_number;   

    // ... 
} 

@Component 
public class CompanyProvider extends JpaProvider<Company, Long> { 
// provides CRUD methods via an EntityManager 
} 

(JPAProvider設置供參考:)

public abstract class JpaProvider<T, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T>, QueryDslPredicateExecutor<T> { 

    @PersistenceContext 
    private EntityManager em; 

應用程序A將公司擴展到CompanyDefault,添加自己的列但不更改DAO。應用程序B也應該這樣做:

@Entity 
@Table(name = "company") 
public class CompanyDefault extends Company {  

    private String name; 

} 

persistence.xml中的每個應用程序(或單元測試)存在一次所以這應該定義實際的實體:

<persistence ... > 
    <persistence-unit name="persistanceUnit" transaction-type="RESOURCE_LOCAL"> 

    <class>path.to.CompanyDefault</class> 

    </persistence-unit> 
</persistence> 

我們創建公司我做以下:

@Inject 
private CompanyProvider companyProvider;  

@Test 
public void testAbstractCompany() { 
    Company company = new CompanyDefault("123"); 
    ((CompanyDefault)company).setName("test"); 

    companyProvider.save(company); 
} 

的不令人滿意的結果是ConstraintVioloationException告訴我,我有主鍵重複的條目:

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert: [...CompanyDefault] 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1215) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1148) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1154) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:678) 
    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.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240) 
    at $Proxy37.persist(Unknown Source) 
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:328) 
    at ....JpaProvider.save(JpaProvider.java:287) 
    at ....JpaProvider$$FastClassByCGLIB$$2caf68f6.invoke(<generated>) 
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191) 
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:617) 
    at ....CompanyProvider$$EnhancerByCGLIB$$d3a45b31.save(<generated>) 
    at ....PersonManagerTest.testAbstractCompany(PersonManagerTest.java:111) 
    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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180) 
    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:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [....CompanyDefault] 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) 
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2454) 
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2854) 
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71) 
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273) 
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:320) 
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203) 
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129) 
    at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69) 
    at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179) 
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135) 
    at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61) 
    at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808) 
    at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782) 
    at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:672) 
    ... 42 more 
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '8' for key 'PRIMARY' 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513) 
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:406) 
    at com.mysql.jdbc.Util.getInstance(Util.java:381) 
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1038) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3563) 
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3495) 
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1959) 
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2113) 
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2693) 
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2102) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2395) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2313) 
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2298) 
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2437) 
    ... 56 more 

現在爲什麼會hibernate試圖持續兩次相同的實體?

我的設置和註釋怎麼樣?

是我們想要做的事:通過使用抽象類的擴展來保存實體?

非常感謝您的幫助!

編輯:

,如果我創建並保存在延對象同樣的情況:

@Test 
public void testAbstractCompany() {  
    CompanyDefault companyDefault = new CompanyDefault("123"); 
    companyProvider.save(companyDefault); 
} 

EDIT2 - 解決:

別介意我的文字牆,解決了這個問題已經..只是一個簡單的錯誤複製谷歌結果:

顯然必須使用InheritanceType.SINGLE_TABLE。我會盡快關閉它。

+0

謝謝@Pete ... edit2解決了我的問題=) – adelarsq

回答

2

根據編輯2解決:抱歉打擾你。