Hibernate没问题,但是ElipseLink失败了:类[Y]的属性[x]被映射到数据库更新中的主键列不允许

时间:2012-07-12 08:40:31

标签: hibernate jpa eclipselink

我有一个非常简单的基于控制台(不是应用程序服务器部署)的JPA程序,我对EclipseLink和Hibernate提供程序进行了测试。所有代码都是JPA所以我想我能够毫无问题地切换提供商。但是,当使用Hibernate作为提供程序但在EclipseLink中失败时,程序会成功。

关键部分是这个(我在防火墙后面,所以我看不到格式化,因为“SO需要来自其他域的JavaScript ......”所以如果格式不正确就道歉 - 我会从家里做格式化) :

em.getTransaction().begin();
Employee emp = service.createEmployee(id, "John Doe", 45000,1);
em.getTransaction().commit();                                        
System.out.println("Persisted "+emp);
em.getTransaction().begin();
em.getTransaction().commit();

我曾经在第二个空事务中做了一些事情,但是在缩小问题范围时,我注意到即使我只是在没有做任何事情的情况下立即开始()和commit(),它也会失败。有趣的部分是EclipseLink(参见帖子底部的stack-trace)似乎抱怨实体Specialty的id属性正在更新,尽管它不是。

Employee实体具有Specialty实体的外键(每个Employee都有一个Specialty),即Employee中的Many-To-One关系:

 @Entity
 public class Employee {
 @Id                                                            
 @Basic(optional = false)                                       
 @NotNull                                                       
 private int id;                                                
 private String name;                                           
 private long salary;                                           
 @JoinColumn(name = "spc_id", referencedColumnName = "id")      
 @ManyToOne(optional = false)                                   
 private Specialty spcId;
 ...}

并且Specialty类定义为:

@Entity                                                  
public class Specialty {                                 
@Id                                                  
@Basic(optional = false)                             
@NotNull                                             
private int id;
... }

当使用Hibernate作为JPA提供程序时,代码可以顺利执行。使用EclipseLink时,它会失败,并在此帖子的底部找到堆栈跟踪。

更新: 经过进一步的实验,我发现以下代码适用于两个提供者:

em.getTransaction().begin();                                      
Employee emp = service.createEmployee(id, "John Doe", 45000, 1);  
em.getTransaction().commit();                                     
System.out.println("Persisted " + emp);                           
EntityManager em2 = emf.createEntityManager();
em2.getTransaction().begin();                                     
em2.getTransaction().commit();                                    
em2.close();          

这仍然无法解释为什么EclipseLink在尝试在同一个实体管理器对象上开始()/ commit()事务时失败的原因(em - 请参阅帖子开头的代码),以及为什么它失败了这么神秘消息(抱怨更新类专业的主键)。

STACK TRACE:

[java] [EL Info]: 2012-07-12 11:21:09.453--ServerSession(23846608)--EclipseLink, version: Eclipse Persistence Services - 2.4.0.v20120608-r11652
 [java] [EL Info]: connection: 2012-07-12 11:21:09.59--ServerSession(23846608)--file:/home/mperdikeas/playground/jpa/01-employee-job/prj/use/build/employeetest.jar_EmployeeService login successful
 [java] Exception in thread "main" javax.persistence.RollbackException: Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.ValidationException
 [java] Exception Description: The attribute [id] of class [mp.Specialty] is mapped to a primary key column in the database. Updates are not allowed.
 [java]     at org.eclipse.persistence.internal.Persisted mp.Employee@ea70f2
 [java] [EL Warning]: 2012-07-12 11:21:09.735--UnitOfWork(32118258)--Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.ValidationException
 [java] Exception Description: The attribute [id] of class [mp.Specialty] is mapped to a primary key column in the database. Updates are not allowed.
 [java] [EL Info]: connection: 2012-07-12 11:21:09.738--ServerSession(23846608)--file:/home/mperdikeas/playground/jpa/01-employee-job/prj/use/buildjpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:102)
 [java]     at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:63)
 [java]     at mp.EmployeeTest.main(EmployeeTest.java:29)
 [java] Caused by: Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.ValidationException
 [java] Exception Description: The attribute [id] of class [mp.Specialty] is mapped to a primary key column in the database. Updates are not allowed.
 [java]     at org.eclipse.persistence.exceptions.ValidationException.primaryKeyUpdateDisallowed(ValidationException.java:2458)
 [java]     at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.writeFromObjectIntoRowWithChangeRecord(AbstractDirectMapping.java:1214)
 [java]     at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildRowForUpdateWithChangeSet(ObjectBuilder.java:1378)
 [java]     at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.updateObjectForWriteWithChangeSet(DatabaseQueryMechanism.java:1003)
 [java]     at org.eclipse.persistence.queries.UpdateObjectQuery.executeCommitWithChangeSet(UpdateObjectQuery.java:84)
 [java]     at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:286)
 [java]     at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
 [java]     at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:852)
 [java]     at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:751)
 [java]     at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108)
 [java]     at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
 [java]     at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2875)
 [java]     at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1602)
 [java]     at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1584)
 [java]     at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1535)
 [java]     at org.eclipse.persistence.internal.sessions.CommitManager.commitChangedObjectsForClassWithChangeSet(CommitManager.java:265)
 [java]     at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:128)
 [java]     at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:3914)
 [java]     at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1419)
 [java]     at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:634)
 [java]     at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1509)
 [java]     at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:266)
 [java]     at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1147)
 [java]     at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:84)
 [java]     ... 2 more
 [java] /employeetest.jar_EmployeeService logout successful

3 个答案:

答案 0 :(得分:2)

EclipseLink不允许您更新PK(如果此PK没有任何FK,某些DBMS允许这样做)

有两种解决方法:

  1. 尝试删除旧记录,然后插入新记录。
  2. 使用代理PK代替业务PK(您仍然可以在业务PK字段上添加唯一约束),在这种情况下,虚拟代理键不会被更改 这是一个comparison between both keys

答案 1 :(得分:0)

可能是:

@Entity                                                  
public class Specialty {                                 
@Id                                                  
@Basic(optional = false)                             
@NotNull
@GeneratedValue(strategy = GenerationType.AUTO)                                         
private int id;
... }

答案 2 :(得分:0)

根据http://blogs.nologin.es/rickyepoderi/index.php?/archives/95-Weaving-Problem-in-EclipseLink.html尝试<property name="eclipselink.weaving.internal" value="false"/>