首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >EclipseLink:“不允许更新”对本机查询插入到

EclipseLink:“不允许更新”对本机查询插入到
EN

Stack Overflow用户
提问于 2014-12-15 12:30:19
回答 2查看 2.1K关注 0票数 1

自从从El2.1升级到EclipseLink 2.5之后,我们在以前运行的代码上得到了一个PersistenceException。悬链很简单:我们有两个相同的表,唯一的区别是,一个是另一个的“历史”版本。基本上,当我们确定某一行不再改变时,我们将该行移到历史表中。这意味着,虽然id是在第一个表上生成的,但它是在历史表上“继承”的。以下是这些实体:

代码语言:javascript
复制
@Entity
@Table(name = "DOCUMENT")
public class Document implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long id;
    // Some other fields
}

@Entity
@Table(name = "DOCUMENT_HISTORY")
public class DocumentHistory implements Serializable {
    @Id
    private long id;
    // Some other fields
}

为了将一行移动到历史表,我们使用了一个本机查询(因为有些列没有映射为实体类中的字段):

代码语言:javascript
复制
String query = "INSERT INTO DOCUMENT_HISTORY SELECT * FROM DOCUMENT t WHERE t.id=?1";
Query updateQuery = entityManager.createNativeQuery(query);
updateQuery.setParameter(1, document.getId());
updateQuery.executeUpdate();

执行此查询时,有时会引发此异常:

代码语言:javascript
复制
javax.persistence.PersistenceException: Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): 
org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [id] of class [org.myc.entities.jpa.company.DocumentHistory] is mapped to a primary key column in the database. Updates are not allowed.
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:868)
    at org.eclipse.persistence.internal.jpa.QueryImpl.performPreQueryFlush(QueryImpl.java:963)
    at org.eclipse.persistence.internal.jpa.QueryImpl.executeUpdate(QueryImpl.java:296)
    at org.myc.utility.jpa.user.DocumentManager.toDocumentHistory(DocumentManager.java:141)
    at java.lang.Thread.run(Thread.java:662)
Caused by: Exception [EclipseLink-7251] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [id] of class [org.myc.entities.jpa.company.DocumentHistory] is mapped to a primary key column in the database. Updates are not allowed.
    at org.eclipse.persistence.exceptions.ValidationException.primaryKeyUpdateDisallowed(ValidationException.java:2548)
    at org.eclipse.persistence.mappings.foundation.AbstractDirectMapping.writeFromObjectIntoRowWithChangeRecord(AbstractDirectMapping.java:1257)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildRowForUpdateWithChangeSet(ObjectBuilder.java:1768)
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.updateObjectForWriteWithChangeSet(DatabaseQueryMechanism.java:1030)
    at org.eclipse.persistence.queries.UpdateObjectQuery.executeCommitWithChangeSet(UpdateObjectQuery.java:84)
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:301)
    at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
    at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:798)
    at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108)
    at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1793)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1775)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1726)
    at org.eclipse.persistence.internal.sessions.CommitManager.commitChangedObjectsForClassWithChangeSet(CommitManager.java:267)
    at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:192)
    at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:138)
    at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4196)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1441)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithPreBuiltChangeSet(UnitOfWorkImpl.java:1587)
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.writeChanges(RepeatableWriteUnitOfWork.java:452)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:863)
    ... 5 more

有人也有同样的问题吗?为什么您认为这种情况不会发生在所有行上,而只发生在其中的一些行(没有明显的特定特性)?谢谢你,吕克

P.S.:EL对本地查询执行映射/查询验证是否正确?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-16 10:32:50

好的,我发现了这个问题,它和那个查询一点关系都没有,所以我仍然不知道为什么会抛出异常。问题是,我们没有使用entityManager.find()获取新插入的历史记录行,而是创建了一个没有附加到持久性上下文的DocumentHistory实例(ID相同),然后使用该实例执行其他操作。希望它能帮到别人。

票数 0
EN

Stack Overflow用户

发布于 2014-12-16 00:42:29

正如JPA2.0规范所述,executeUpdate()执行update或delete语句,因此不支持insert。

通过使用EntityManager (在事务中)持久化并刷新实体,可以将实体插入到底层数据库中。在您的特定情况下,一个虚拟示例可能如下所示:

代码语言:javascript
复制
// transaction starts
Document doc = em.find(Document.class, id);
DocumentHistory docHistory = new DocumentHistory(doc);
em.persist(docHistory);
// transaction ends

注意到:您可以考虑使用EclipseLink审计特性,而不是私有解决方案(这很好):

EclipseLink还支持完整的历史支持,它允许在镜像历史表中跟踪对数据库所做的所有更改的完整历史记录。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27484162

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档