2016-09-23 14 views
0

私はこのコードのビットをDBに保存され、新たな(つまりは、まだデータベースに存在しない)JPAエンティティ持っEntityExistsExceptionを投げる:OpenJPAのが不規則

public abstract class Dao { 
    @PersistenceContext(name = "puOpenJPA_Core",type = PersistenceContextType.TRANSACTION) 
    private EntityManager em; 

    public void save(Fund entity) { 
     entity = em.merge(entity); 
     em.flush(); 

     // do something with entity.fundId 
    } 
} 

を我々はIDを使用しているため、私たちはflushを必要としますオブジェクトに他のものを移入させ、IDがDB上に生成される。

エンティティは次のようになります。

@Entity 
public class Fund extends AbstractFund implements Serializable 
{ 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "fundId") 
    protected Long id; 

    // other fields and getters etc. 

} 

AbstractFundは、より多くのフィールドを持つ抽象マッピングされたスーパークラスです。

データベースのテーブルには、IDとして定義されたfundId列があります。 これは長い間、すべて正常に動作しています。しかし、flushが呼び出されたときに断続的なエラーが発生しています。展開後のコードでは、しばらくの間、正常に動作し、その後、突然、この例外をスローを開始:

Caused by: <openjpa-2.3.0-r422266:1540826 fatal general error> org.apache.openjpa.persistence.PersistenceException: 
The transaction has been rolled back. See the nested exceptions for details on the errors that occurred. 
FailedObject: [email protected] 
     at org.apache.openjpa.kernel.BrokerImpl.newFlushException(BrokerImpl.java:2370) [openjpa-all-2.3.0.jar:2.3.0] 
     at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:2207) [openjpa-all-2.3.0.jar:2.3.0] 
     at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2105) [openjpa-all-2.3.0.jar:2.3.0] 
     at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1876) [openjpa-all-2.3.0.jar:2.3.0] 
     at org.apache.openjpa.kernel.DelegatingBroker.flush(DelegatingBroker.java:1045) [openjpa-all-2.3.0.jar:2.3.0] 
     at org.apache.openjpa.persistence.EntityManagerImpl.flush(EntityManagerImpl.java:663) [openjpa-all-2.3.0.jar:2.3.0] 
     at org.jboss.as.jpa.container.AbstractEntityManager.flush(AbstractEntityManager.java:457) [wildfly-jpa-8.1.0.Final.jar:8.1.0.Final] 
     ...... 
Caused by: java.lang.Exception: <openjpa-2.3.0-r422266:1540826 fatal store error> org.apache.openjpa.persistence.EntityExistsException: 
Cannot insert explicit value for identity column in table 'Fund' when IDENTITY_INSERT is set to OFF. {prepstmnt 2128975916 INSERT INTO Fund 
(fundId, ... other columns ...) VALUES (?, ?, ?,)} [code=544, state=23000] 
FailedObject: [email protected] 
     at org.apache.openjpa.util.Exceptions.replaceNestedThrowables(Exceptions.java:255) [openjpa-all-2.3.0.jar:2.3.0] 
     at org.apache.openjpa.persistence.PersistenceException.writeObject(PersistenceException.java:100) [openjpa-all-2.3.0.jar:2.3.0] 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_60] 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_60] 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_60] 
     at java.lang.reflect.Method.invoke(Method.java:606) [rt.jar:1.7.0_60] 
     at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271) 
     at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:290) 
     at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:245) 
     at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:125) 
     at org.jboss.marshalling.cloner.SerializingCloner.cloneFields(SerializingCloner.java:341) 
     at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:293) 
     at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:277) 
     at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:277) 
     at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:277) 
     at org.jboss.marshalling.cloner.SerializingCloner.initSerializableClone(SerializingCloner.java:277) 
     at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:245) 
     at org.jboss.marshalling.cloner.SerializingCloner.clone(SerializingCloner.java:125) 
     at org.jboss.as.ejb3.remote.LocalEjbReceiver.clone(LocalEjbReceiver.java:314) [wildfly-ejb3-8.1.0.Final.jar:8.1.0.Final] 
     at org.jboss.as.ejb3.remote.LocalEjbReceiver.clone(LocalEjbReceiver.java:297) [wildfly-ejb3-8.1.0.Final.jar:8.1.0.Final] 
     at org.jboss.as.ejb3.remote.LocalEjbReceiver.processInvocation(LocalEjbReceiver.java:249) [wildfly-ejb3-8.1.0.Final.jar:8.1.0.Final] 
     ... 126 more 

私は他の環境でこれを再作成することができませんでしたし、OpenJPAのが突然挿入しようとし始めるだろう理由として途方に暮れていますしていますID列の値。

OpenJPAバージョン2.3.0を使用しています。

バージョン2.4.1にアップデートしようとしましたが、問題は解決しません。

+0

私はテーブル 'Fund'はすでに問題を引き起こしているいくつかの古い行を持っている場合は疑いますか? –

+0

そうは思われません - SQLエラーは、それがID列の挿入に関するものであることが非常に限定的です。 –

+1

エラーは明示的で、IDフィールドに値を挿入できないことを示しています。既にIDフィールドが設定されているエンティティに対してmergeを呼び出しています。この例外が発生したときに何をマージしていますか?また、SQLのログオンをオンにして、挿入/更新/削除を確認して、なぜこの問題が発生したかを追跡できます。私の推測では、あなたはエンティティを削除して、それを元に戻そうとしています、そして、IDフィールドはあなたに許されません。 – Chris

答えて

-1

最初にオブジェクトを取得して新しいオブジェクトを作成し、取得したオブジェクトから新しいオブジェクトにプロパティをコピーし、そのオブジェクトを新しいオブジェクトのpersistメソッドで呼び出す必要があります。 BeanUtils.copyPropertiesメソッドを使用すると、ソースオブジェクトからターゲットオブジェクトにプロパティをコピーすることができます。また、独自の方法でプロパティをコピーすることもできます。

+0

私はオブジェクトが新しいものであるとはっきりしていなかったので、DBには存在しません。 –

2

まず、尊敬の念を払って、Prashant Kataraがどこで答えようとしているのか分かりません。私は選択/コピー/永続化を行う必要があるシナリオを認識していませんか? Chrisは良いコメントを提供しました。この問題がどのように起こったのか正確には言えませんが、あなたが指摘しているように、自分自身を問題に陥らせたり、散発的に、あるいは環境に特化させる方法についての情報を提供しましょう。あなたの説明では、あなたがこの「保存」メソッド掲載:

public void save(Fund entity) { 
    em.merge(entity); 
    em.flush(); 
} 

をあなたはその後、「我々は、IDを使用しているため、私たちは.....フラッシュを必要とする」と述べました。ここにはいくつかの事柄があります。ご覧のとおり、渡された「エンティティ」をマージして保存します。しかし、 'em.merge'から返されたオブジェクトを返すことはありません。 OpenJPAは 'entity'のidを移入するのではなく、mergeが返すid値のみを移入します。人は、マージに渡されたインスタンスがマネージインスタンスではないことを常に忘れています! mergeから返されたインスタンスは管理されます。あなたはidの値が必要だと述べたので、実際にはsaveの呼び出しの後で 'entity'を使用していると仮定します。したがって、マネージインスタンス(つまり 'em.merge'によって返されたインスタンス)を使用する必要があります。これは安全な操作ではないので、フラッシュした後でもfundIdのgetterメソッドを呼び出すと「null」にならないのは驚きです。あなたが決してNEVERを繰り返さない場合は、呼び出しの後に 'entity'を使用して保存してください。あなたの保存方法は問題ありません。あなたは後に保存したエンティティを引き続き使用する場合しかし、その後、あなたの保存は次のようになります。

public Fund save(Fund entity) { 
    Fund entityPrime = em.merge(entity); 
    em.flush(); 
    return entityPrime; 
} 

最後に、OpenJPAが識別フィールドのフィールド/列を含むINSERTを発行しません。したがって、そこに資金を入れたINSERTは決して見るべきではありません。あなたのINSERTに資金が含まれているケースにどのように入ってきたのかは私を超えています。クラスパスのどこかに '@GeneratedValue(strategy = GenerationType.IDENTITY)'が含まれていない古いバージョンのFundがある可能性があります。 INSERT操作の一部として、IDENTIFICATION値がデータベースから戻され、OpenJPAはその戻り値を(管理された)IDENTIFICATIONフィールドに割り当てます。

おかげで、

ヒース

+0

ありがとう、ヒース、あなたの言うことは意味をなさない、私は私たちがインサートに資金を見てはならないということに同意する。私は貼り付けたコードを間違えた。エンティティを 'merge'メソッドから返された値に設定します。 –

+0

Ok Seanので、更新されたコードでも同じ問題が発生します(つまり、mergeによって返されたインスタンスを使用しています)。もしそうなら、私はこれの一番下に行くことができる唯一の方法は、エンティティ全体とあなたのユースケースのスニペットを添付(または貼り付け)することだと思います...私はTxがいつ開始/コミット、およびマージ/フラッシュを実行したとき(エンティティマネージャの呼び出しがあった場合)また、Fund.classのクラスパス全体を検索することをお勧めします。問題の散発的な(またはenv固有の)性質を指定します。OpenJPAが、資金IDがIDENTITYではないと考えられる古いメタデータを見つけることができるのだろうか。 –

関連する問題