18

当我尝试更改我@ID@Entity.

identifier of an instance of com.google.search.pagerank.ItemEntity was altered from 1 to 2.

我知道我正在更改表中的主键。我正在使用 JPA 注释。

我通过使用这个单一的 HQL 查询解决了这个问题:update Table set name=:newName where name=:oldName

而不是使用更多的OO方法:

beginTransaction();
T e = session.load(...);
e.setName(newName);
session.saveOrUdate(e);
commit();

知道差异是什么吗?

4

4 回答 4

22

实际上,根据 JPA 规范,禁止更改主键:

应用程序不得更改主键的值[8]。如果发生这种情况,则行为未定义。 [9]

(来自 EJB 3 持久性 (JPA) 规范,第 2.1.4 段)

于 2010-02-07T14:31:12.830 回答
10

我无法想象你为什么要这么做。完全没有。为什么要更改实体的身份?您还需要更新指向它的其他表中的所有外键。好像很痛苦,没有收获。您最好将其设为“业务密钥”(普通属性)并使用更永久的代理密钥。我有一种感觉,你做这一切都错了,但如果你坚持...

本质上,您所做的是创建一个新客户并删除旧客户,这就是我在 Hibernate 中完成它的方式。

[伪代码]

Begin Transaction

// create new customer from old
newC = Session.Load<Customer>(42)
Session.Evict(newC)
newC.Id = 1492
Session.Save(newC)

// update other relationships to point to newC
// ....

// delete old customer
oldC = Session.Load<Customer>(42)
Session.Delete(oldC)

Commit Transaction

但是,您最好只在一个普通的单个 SQL 事务中一次完成所有操作,并且在任何一种情况下,您都可能面临已经拥有“旧”客户实例的并行进程的风险,这可能会导致一些错误。

于 2009-04-10T15:45:39.873 回答
4

我的朋友,你是对的。如果不使用 HQL 语句,就无法(或者我不知道如何)更改主键。这不正常,但这是真的。

于 2009-06-12T09:04:20.253 回答
3

这不是一个解决方案,因为我相信上面已经回答了。

但是,我想提供我认为是想要这样做的有效方案。(欢迎评论)

1) 表 USER_ELECTRONICS 与表 ELECTRONICS_DEF 多对多

2)这个多对多是一个有序列表。每个 USER_ELECTRONIC_ID 都有一个 ELECTRONICS_DEF_ID 的优先列表。例如,我有一部 iPhone、一部 iPad、手机,我按照我喜欢它们的程度对它们进行排名。为了做到这一点,我有 USER_ELEC_PRIORITY_MAP 表,看起来像这样 -

USER_ELEC_ID ELEC_DEF_ID PRIORITY

1 IPAD 1
1 IPHONE 2
1 CELL 3

USER_ELEC_ID 和 ELEC_DEF_ID 是 PFK。优先级是复合 FK。

3) 当我想根据我的偏好重新编排表格时(我的新 iPad2 位居榜首,iPad 移动到 #4),我需要更新部分复合 FK(优先级)。

于 2011-03-25T17:55:14.233 回答