2013-04-26 61 views
0

嘗試持久化新實體時遇到問題。我使用Eclipselink 2.4.2作爲實體管理器。 Store方法中的BaseDao類在將其作爲新的持久化(persist-> flush-> refresh)刷新並刷新實體之後。所有事情都在一次交易中發生。在同步異常期間級聯PERSIST

我的實體是這樣的(部分我擔心):

TrustEntity { 
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "trust", cascade = {CascadeType.ALL}) 
    @PrivateOwned 
    private List<TrustIncentiveRateEntity> trustIncentiveRates; 
} 

TrustIncentiveRateEntity { 
    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "TRUST_ID", nullable = false) 
    private TrustEntity trust; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "trustIncentiveRate", cascade = {CascadeType.ALL}) 
    @PrivateOwned 
    private List<TrustIncentiveRateValueEntity> trustIncentiveRateValues; 
} 

TrustIncentiveRateValueEntity { 
    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "TRUST_INCENTIVE_RATE_ID", nullable = false) 
    private TrustIncentiveRateEntity trustIncentiveRate; 
} 

我創建一個新的信託實體,實例化一個TrustIncentiveRateEntity列表,在其中創建一個新的元素,實例化一個TrustIncentiveRateEntity並在其中創建一個新元素。 在調試過程中,我可以看到所有引用都是正確的。

現在,當我試圖在這裏堅持,這是發生了什麼:

從服務器日誌:

FINE: SELECT SEQ_TRUST.NEXTVAL FROM DUAL 

FINE: SELECT SEQ_TRUST_INCENTIVE_RATE.NEXTVAL FROM DUAL 

FINE: SELECT SEQ_TRUST_INCENTIVE_RATE_VALUE.NEXTVAL FROM DUAL 

FINE: INSERT INTO TRUST (TRUST_ID, ACTION_DATE, ACTION_USER_ID, IS_ACTIVE, CREATION_DATE, CREATION_USER_ID, IS_INCENTIVE_ACTIVE, IS_NO_CREDIT_LIMIT, PROCESS_CURRENT_STATUS, REMARKS, STATUS_INCENTIVE, TRUST_CODE, TRUST_NAME, TRUST_TYPE, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, STRUCTURAL_ORG_UNIT_SALES_ID, STRUCTURAL_ORG_UNIT_ID, USER_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
    bind => [38007, 2013-04-26 09:46:31.582, 1003186, true, 2013-04-26 07:46:34.659, 1003186, true, false, OPEN, null, OPEN, 100058, 741963852, T, null, null, 1, 387, 387, 1003186] 

FINE: INSERT INTO TRUST_INCENTIVE_RATE (TRUST_INCENTIVE_RATE_ID, CREATION_DATE, CREATION_USER_ID, EQUIPMENT_SIZE, EXTENDED_EQ_GROUP_ID, RATE_BASIS, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, TRADE_ID, TRUST_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
    bind => [15001, 2013-04-26 07:46:39.862, 1003186, 20, 2, B, null, null, 1, 144001, 38007] 

FINE: INSERT INTO TRUST_INCENTIVE_RATE_VALUE (TRUST_INCENTIVE_RATE_VALUE_ID, CREATION_DATE, CREATION_USER_ID, EFFECTIVE_DATE, EXPIRY_DATE, INCENTIVE, STATUS, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, CURRENCY_CODE, TRUST_INCENTIVE_RATE_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
    bind => [14007, 2013-04-26 07:46:39.955, 1003186, 2013-04-26 00:00:00.0, 9999-12-31 00:00:00.0, 12, OPEN, null, null, 1, USD, 15001] 

FINE: SELECT TRUST_ID, ACTION_DATE, ACTION_USER_ID, IS_ACTIVE, CREATION_DATE, CREATION_USER_ID, IS_INCENTIVE_ACTIVE, IS_NO_CREDIT_LIMIT, PROCESS_CURRENT_STATUS, REMARKS, STATUS_INCENTIVE, TRUST_CODE, TRUST_NAME, TRUST_TYPE, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, STRUCTURAL_ORG_UNIT_SALES_ID, STRUCTURAL_ORG_UNIT_ID, USER_ID FROM TRUST WHERE (TRUST_ID = ?) 
    bind => [38007] 

FINE: SELECT TRUST_INCENTIVE_RATE_ID, CREATION_DATE, CREATION_USER_ID, EQUIPMENT_SIZE, EXTENDED_EQ_GROUP_ID, RATE_BASIS, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, TRADE_ID, TRUST_ID FROM TRUST_INCENTIVE_RATE WHERE (TRUST_ID = ?) 
    bind => [38007] 

FINE: SELECT TRUST_INCENTIVE_RATE_VALUE_ID, CREATION_DATE, CREATION_USER_ID, EFFECTIVE_DATE, EXPIRY_DATE, INCENTIVE, STATUS, UPDATE_DATE, UPDATE_USER_ID, VERSION_OPT_LOCK, CURRENCY_CODE, TRUST_INCENTIVE_RATE_ID FROM TRUST_INCENTIVE_RATE_VALUE WHERE (TRUST_INCENTIVE_RATE_ID = ?) 
    bind => [15001] 

到目前爲止好,但是當交易被EntityManager的COMMITED我得到下面的異常:

WARNING: java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: [email protected] 
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.discoverUnregisteredNewObjects(RepeatableWriteUnitOfWork.java:303) 
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:706) 
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1498) 
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:3151) 
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:345) 
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:158) 
at org.eclipse.persistence.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:68) 
at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:435) 
at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:855) 
at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5136) 
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4901) 
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2045) 
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1994) 
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:222) 
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88) 
at $Proxy241.save(Unknown Source) 

這對我來說似乎很奇怪,像EM試圖TrustIncentiveRateEntity前實際存儲TrustIncentiveRateValueEntity並不能看到TrustIncen tiveRateEntity。 看過類似的線程後,我已將CascadeType.PERSIST添加到TrustIncentiveRateValueEntity類中的trustIncentiveRate字段上的@ManyToOne註釋中。之後,情況如下所示:EM像之前那樣插入實體,然後從SEQ_TRUST_INCENTIVE_RATE獲取nextval,並嘗試再次插入TrustIncentiveRateValueEntity(使用新ID,但其餘字段值保持不變)。它導致約束違規,因爲我在這些表列的某些橫截面上有一個唯一的約束。異常,交易回滾,我仍然難過。

我的存儲方法在BaseDao類:

@TransactionAttribute(TransactionAttributeType.MANDATORY) 
public T_ENTITY store(T_ENTITY entity) { 
    if (!entity.isNewlyCreated()) { 
     T_ENTITY mergedEntity = em.merge(entity); 
     flush(); 
     return mergedEntity; 
    } else { 
     try { 
      em.persist(entity); 
      flush(); 
      refresh(); 
     } catch (RuntimeException exc) { 
      entity.resetPersistentFlag(); 
      throw exc; 
     } 
     return entity; 
    } 
} 

但調用em.persist(實體)直接,無需沖洗/刷新導致同樣的問題。

服務調用的邏輯:

@Override 
@TransactionAttribute(TransactionAttributeType.REQUIRED) 
public TrustEntity save(TrustEntity dto) { 
    TrustEntity trust = trustDao.store(trust); 

    workflowConversation.triggerWorkflow(); // doesn't do anything to any of the entities when they are freshly created 

    return trust; 
} 

任何人都可以幫助我識別什麼可能是錯誤的呢?

+0

如果你得到一個重複的TrustIncentiveRateEntity當您添加的TrustIncentiveRateValueEntity.trustIncentiveRate關係級聯堅持,那麼就意味着有你的對象樹兩種不同TrustIncentiveRateEntity實例。你如何檢查它們在你的調試中是否一樣,並且你可能在實體中有可能改變引用的事件或get/set方法?例如,如果您正在使用屬性訪問和包含的業務邏輯來設置JPA必須使用的set方法中的後臺指針。 – Chris 2013-04-26 17:09:30

回答

0

您不能有一個OneToMany同時使用一個mappedby,使其成爲雙向,並且一個連接列將其標記爲單向。它們發生衝突並導致您的問題。

當您將關係標記爲mappedby時,您指定關係的所有信息和控制權位於另一端 - 包括聯接列信息。嘗試:

TrustEntity { 
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "trust", cascade = {CascadeType.ALL}) 
    @PrivateOwned 
    private List<TrustIncentiveRateEntity> trustIncentiveRates; 
} 

TrustIncentiveRateEntity { 
    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "TRUST_ID", nullable = false) 
    private TrustEntity trust; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "trustIncentiveRate", cascade = {CascadeType.ALL}) 
    @PrivateOwned 
    private List<TrustIncentiveRateValueEntity> trustIncentiveRateValues; 
} 
+0

謝謝,我自己也已經發現了這一點,但不幸的是,這並沒有解決我的問題,我仍然得到相同的例外。 – 2013-04-26 14:30:04

+0

然後修復您的問題,並且您需要顯示更多信息,因爲問題出現在您省略的其中一個細節中。例如,你提到你堅持,日誌顯示插入,但它顯示選擇遍歷樹。它沒有說明這些選擇是如何或爲何發生的,以及它們如何與交易相關 - 如果它只是一個沖刷,那麼在事務提交之前做了哪些更改以及其他內容呢?錯誤不是因爲堅持 - 你的日誌顯示它們已經被持久化了。它正在發現一個沒有在樹中堅持的對象。 – Chris 2013-04-26 14:42:41

+0

我已經提出了對該問題的建議更改。 至於選擇 - 我認爲他們來自refresh(); – 2013-04-26 15:26:36