tags:

views:

1538

answers:

3

I receive the following exception when Im trying to alter my @ID in an @Entity.

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

I know that im altering the primary key in my table. Im using JPA-annotations.

I solved this by using this single HQL query: update Table set name=:newName where name=:oldName

instead of using the more oo approach:

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

Any idea what the diff is?

+2  A: 

I can't imagine why you'd want to do that. At all. Why would you change an entity's identity? You'd also need to update all the foreign keys in other tables that point to it. Seems like a pain, with no gain. You're probably better off making this a "business key" (plain property) and using a more permanent surrogate key. I have a feeling that you're going about this all wrong, but if you insist...

Essentially what you're doing is creating a new Customer and deleting the old one, and that's how I'd accomplish it in Hibernate.

[pseudocode]

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

However, you're probably better off just doing it in all at once in a plain single SQL transaction, and in either case you risk having parallel processes that already have an instance of the "old" Customer, which might cause some errors.

Winston Fassett
First of all; there are no foreign key constraints to this identity. And ofcourse there are situations when one wants to change the primary key. I can admit that it's not a thing you do every day, but the context can without any doubt create a situation that involes it.
Schildmeijer
Although I can't *imagine* such a scenario, I acknowledge that one might exist. I would *love* to know what this scenario is. Also, any thoughts on the proposed solution?
Winston Fassett
my intentions are not to be rude. my scenario is something like this. I have a table with two columns, nick::string and number::int, where the nick is the primary key. And because of embedded memory constraints we cant afford to add a id like nickId. And people are allowed to change nick
Schildmeijer
your suggestion worked fine, but i ended up with a single HQL statement "update nick set nick = :oldNick where nick = : newNick"
Schildmeijer
but i still dont understand why i had to use HQL instead of entity.setNick(newNick); session.saveOrUpdate(entity);
Schildmeijer
To Hibernate, identifiers are immutable and changing them can mess up collections, proxies, and misc other stuff. So it throws an error, and even if it didn't, the ID is always excluded from generated UPDATE statements. So you have to do the stuff above, or just update via SQL or HQL.
Winston Fassett
+1  A: 

My friend, you are right. There is no way (or I don't know a way) to change primary key without using HQL statements. It's not normal, but it's true.

+3  A: 

Actually, according to the JPA specification it is forbidden to change a primary key:

The application must not change the value of the primary key[8]. The behavior is undefined if this occurs.[9]

(from EJB 3 persistence (JPA) specification, paragraph 2.1.4)

Nir