2012-09-11 4 views
7

EclipseLinkが永続性プロバイダであるJPAプログラムがあります。ユーザーエンティティをマージしてそのIDを変更し、同じユーザーインスタンスを再度マージしようとすると、エラーがスローされます。最も簡単な方法で問題を説明するためにコードを書き直します。エンティティをマージし、IDを変更して再度マージし、「データベースの主キー列にマップされ、更新は許可されません」エラー

User user = userManager.find(1); 
userManager.merge(user); 
System.out.println("User is managed? "+userManager.contains(user); 
user.setId(2); 
userManager.merge(user); 

上記のコードはトランザクションコンテキストにはありません。 userManagerは、EntityManagerが注入されたステートレスセッションBeanです。

User is managed? false 

Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.1.3.v20110304-r9073): org.eclipse.persistence.exceptions.ValidationException 
Exception Description: The attribute [id] of class [demo.model.User] is mapped to a primary key column in the database. Updates are not allowed. 

2番目のmerge()呼び出しで例外が発生します。

私は、新しいユーザーを作成する場合は、そのIDを設定し、それが動作しますが、それをマージ:

User user = userManager.find(1); 
userManager.merge(user); 
System.out.println("User is managed? "+userManager.contains(user); 
User newUser = new User(); 
newUser.setId(2); 
userManager.merge(newUser); 

だから、最初のシナリオ2つ目の違いは何ですか? JPA仕様によれば、エンティティが分離状態にある限り、マージは成功するはずです。 (ID = 2のエンティティが存在すると仮定します)

なぜ、ユーザーエンティティが以前にマージされているという事実に悩まされているようですか?

更新:これはEclipseLinkのバグのようです。私はHibernateにEclipseLinkをから持続性プロバイダを交換しました:

私は

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 

<provider>org.hibernate.ejb.HibernatePersistence</provider>  

にエラーがスローされていない変更します。

+0

あなたのIDは生成された値ですか? – kostja

+0

はい、生成された値です –

答えて

2

これはEclipseLinkのバグのようです。私はHibernateにEclipseLinkをから持続性プロバイダを変更した:

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> 

<provider>org.hibernate.ejb.HibernatePersistence</provider> 

にエラーがスローされていない

から。

EclipseLinkのバージョンは2.3.2です。 (最新のGlassfishアプリケーションサーバー3.1.2に同梱されています)。

hibernateのバージョンは、最新の4.1.7です。

+1

バージョン2.6.3でまだ発生しています –

3

Idは、最初の例で試したように、2番目の例のように挿入/定義できますが、変更/更新はできません。 JPAプロバイダは変更をデータベースに反映しようとし、失敗します。

JPA 2の仕様は、§2.4

アプリケーションは、主キーの値を変更してはならないと言います。これが発生すると、 の動作は未定義です。

+0

エンティティは既にデタッチされています。分離されたエンティティのIDを変更すると、その変更はデータベースに反映されません。 –

+0

@MingtaoSunはい、エンティティが管理されていない場合、エラーは 'setId'ではなく' merge'呼び出しで発生するはずです。それはどこに起こりますか?奇妙なことは、EMによって返されたエンティティが管理されていないと言われています。 EMは、対応する既存のコンテキストに含まれるオブジェクトのみを返すことができるため、管理対象のオブジェクトのみを返します。 'setId'でエラーが発生した場合は、EM上で' detach'または 'clear'を呼び出すことで、エンティティを明示的に切り離してみてください。 – kostja

+0

エラーはsetId()ではなくmerge()で発生しました。 JPA仕様によれば、エンティティがデタッチされると、エンティティをマージすることができます()。 –

0

ごとにこの答えは4年遅れて、とにかくあるpersistence.xmlで<property name="eclipselink.weaving.internal" value="false"/>を試してみてください。あなたが定期的にアップデートを実行することによってそれを更新することができ

は、SQLまたはJPQLまたは基準APIを使用して照会します。私は最後のものが最高だと分かります。

ここでは、このトリックを行うことができるコード例を示します。同様の状況で試してみましたが、EclipseLinkでうまく動作します。

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaUpdate<User> cu = cb.createCriteriaUpdate(User.class); 
Root<User> c = cu.from(User.class); 
cu.set(User_.id, newId).where( cb.equal(c.get(User_.id), oldId) ); 
em.createQuery(cu).executeUpdate(); 

代わりのあなたは、例えばStringとしてのフィールドの名前を渡すことができ User_.id "id"

別の例http://www.thoughts-on-java.org/criteria-updatedelete-easy-way-to/

関連する問題