java 合并一个实体,更改其id,再次合并,导致“映射到数据库中的主键列。不允许更新”错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12364051/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Merge an entity, change its id, merge again, cause "mapped to a primary key column in the database. Updates are not allowed" error
提问by Mingtao Sun
I have a JPA program where EclipseLink is the Persistence provider. When I merge an user entity, change its ID, and try to merge the same user instance again, an error is thrown. I rewrite my code to illustrate my problem in the simplest way.
我有一个 JPA 程序,其中 EclipseLink 是持久性提供程序。当我合并用户实体、更改其 ID 并尝试再次合并同一个用户实例时,会引发错误。我重写了我的代码,以最简单的方式来说明我的问题。
User user = userManager.find(1);
userManager.merge(user);
System.out.println("User is managed? "+userManager.contains(user);
user.setId(2);
userManager.merge(user);
The above code is not in a transaction context. userManager is a stateless session bean with an EntityManager injected. When executed, the console prints:
上面的代码不在事务上下文中。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.
The exception occurs at the second merge() invocation.
异常发生在第二次 merge() 调用中。
If I create a new user, sets its ID and merge it, it works:
如果我创建一个新用户,设置它的 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);
So what is the difference between the first scenario and second one? According to the JPA specification, as long as the entity is in detached state, the merge should succeed, right? (Assuming the entity with ID=2 exists)
那么第一个场景和第二个场景有什么区别呢?根据JPA规范,只要实体处于分离状态,合并就应该成功,对吗?(假设ID=2的实体存在)
Why the EclipseLink provider seems to be bothered by the fact that the user entity has been merged before?
为什么 EclipseLink 提供者似乎被用户实体之前已合并的事实所困扰?
Update: It seems to be an bug of EclipseLink. I have replaced the persistence provider from EclipseLink to Hibernate:
更新:这似乎是 EclipseLink 的一个错误。我已将持久性提供程序从 EclipseLink 替换为 Hibernate:
I change
我改变
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
to
到
<provider>org.hibernate.ejb.HibernatePersistence</provider>
No error has been thrown.
没有抛出错误。
采纳答案by Mingtao Sun
It seems to be an bug of EclipseLink. I have changed the persistence provider from EclipseLink to Hibernate:
这似乎是 EclipseLink 的一个错误。我已将持久性提供程序从 EclipseLink 更改为 Hibernate:
from
从
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
to
到
<provider>org.hibernate.ejb.HibernatePersistence</provider>
No error has been thrown.
没有抛出错误。
The version of EclipseLink is 2.3.2. (which is shipped with the latest Glassfish application server 3.1.2).
EclipseLink 的版本是 2.3.2。(随最新的 Glassfish 应用程序服务器 3.1.2 一起提供)。
The version of hibernate is, as of now the latest, 4.1.7.
到目前为止,hibernate 的最新版本是 4.1.7。
回答by kostja
The reason is that the Id
may be inserted/defined - as you do in your second example, but not changed/updated - as you try in your first example. The JPA provider tries to reflect the change in the database and fails.
原因是Id
可以插入/定义 - 就像您在第二个示例中所做的那样,但没有更改/更新 - 正如您在第一个示例中尝试的那样。JPA 提供程序尝试反映数据库中的更改并失败。
JPA 2 spec §2.4 says
JPA 2 规范 §2.4 说
The application must not change the value of the primary key. The behavior is undefined if this occurs.
应用程序不得更改主键的值。如果发生这种情况,则行为未定义。
回答by vnysmnn
Try <property name="eclipselink.weaving.internal" value="false"/>
in persistence.xml as per
http://blogs.nologin.es/rickyepoderi/index.php?/archives/95-Weaving-Problem-in-EclipseLink.html
<property name="eclipselink.weaving.internal" value="false"/>
按照http://blogs.nologin.es/rickyepoderi/index.php?/archives/95-Weaving-Problem-in-EclipseLink.html在persistence.xml 中
尝试
回答by Theofanis
This answer is 4 years late but anyway.
这个答案晚了 4 年,但无论如何。
You can update it by executing regular update queriesusing SQL or JPQLor Criteria API. I find the last one is the best.
您可以通过使用 SQL 或JPQL或Criteria API执行定期更新查询来更新它。我觉得最后一个是最好的。
Here is a code example that can do the trick. I have tried it in a similar situation and it works fine with EclipseLink.
这是一个可以解决问题的代码示例。我在类似的情况下尝试过它,它与 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();
Instead of User_.idyou can pass the name of the field as a String e.g. "id".
您可以将字段名称作为字符串传递,而不是User_.id,例如"id"。
Another example http://www.thoughts-on-java.org/criteria-updatedelete-easy-way-to/
另一个例子http://www.thoughts-on-java.org/criteria-updatedelete-easy-way-to/