2009-04-09 3 views
17

Ich erhalte die folgende Ausnahme, wenn ich versuche, meine @ID in einem @Entity zu verändern.Hibernate, ändern Kennung/Primärschlüssel

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

Ich weiß, dass ich den Primärschlüssel in meiner Tabelle ändern. Ich verwende JPA-Anmerkungen.

Ich löste dies durch diese einzelne HQL Abfrage: update Table set name=:newName where name=:oldName

Statt die mehr OO Ansatz der Verwendung:

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

Jede Idee, was der Unterschied ist?

+0

Versuchen Sie eine andere Entität als PK zu verwenden? –

+0

Jetzt versuche ich meinen privaten Schlüssel von einer persistenten Entität zu ändern. In SQL wäre es etwa so: "update Kunden setzen customerId = 1492 where customer_id = 42;" und customer_id ist mein privater Schlüssel – Schildmeijer

Antwort

10

Ich kann mir nicht vorstellen, warum Sie das tun wollen würde. Überhaupt. Warum änderst du die Identität einer Entität? Sie müssen auch alle Fremdschlüssel in anderen Tabellen aktualisieren, die auf sie zeigen. Scheint wie ein Schmerz, ohne Gewinn. Es ist wahrscheinlich besser, wenn Sie dies zu einem "Geschäftsschlüssel" (einfache Eigenschaft) machen und einen dauerhafteren Ersatzschlüssel verwenden. Ich habe das Gefühl, dass du das alles falsch machst, aber wenn du darauf bestehst ...

Im Wesentlichen musst du einen neuen Kunden erstellen und den alten löschen, und so würde ich es schaffen in Hibernate.

[Pseudo-Code]

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 

Allerdings sind Sie wahrscheinlich besser dran, es einfach zu tun in auf einmal in einer einfachen einzigen SQL-Transaktion, und in jedem Fall riskieren Sie parallele Prozesse aufweisen, die bereits eine Instanz haben des "alten" Kunden, was einige Fehler verursachen könnte.

+5

Zunächst einmal; Es gibt keine Fremdschlüsseleinschränkungen für diese Identität. Und natürlich gibt es Situationen, in denen man den Primärschlüssel ändern möchte. Ich kann zugeben, dass Sie das nicht jeden Tag tun, aber der Kontext kann ohne Zweifel eine Situation schaffen, die sich auf ihn bezieht. – Schildmeijer

+0

Obwohl ich mir ein solches Szenario nicht vorstellen kann, gebe ich zu, dass es einen geben könnte. Ich würde * gerne * wissen, was dieses Szenario ist. Auch, irgendwelche Gedanken zu der vorgeschlagenen Lösung? –

+0

meine Absichten sind nicht unhöflich. Mein Szenario ist so etwas. Ich habe eine Tabelle mit zwei Spalten, nick :: string und number :: int, wobei der Spitzname der Primärschlüssel ist. Und aufgrund von eingebetteten Speicherbeschränkungen können wir es uns nicht leisten, eine ID wie nickId hinzuzufügen. Und Leute dürfen den Nick ändern – Schildmeijer

3

Mein Freund, Sie haben Recht. Es gibt keine Möglichkeit (oder ich kenne keine Möglichkeit), den Primärschlüssel ohne Verwendung von HQL-Anweisungen zu ändern. Es ist nicht normal, aber es ist wahr.

21

Eigentlich gemäß der JPA-Spezifikation ist es verboten, einen Primärschlüssel zu ändern:

die Anwendung nicht den Wert des Primärschlüssels ändern muß [8]. Das Verhalten ist undefiniert, wenn dies auftritt. [9]

(von EJB 3 Persistenz (JPA) -Spezifikation, Absatz 2.1.4)

+0

Ich kann das nicht in der endgültigen Version finden. –

3

Dies ist keine Lösung, da ich glaube, dass oben beantwortet wurde.

Allerdings wollte ich anbieten, was ich für ein gültiges Szenario hielt, um dies zu tun. (Kommentare erlaubt)

1) Tabelle USER_ELECTRONICS hat eine many-to-many-Tabelle ELECTRONICS_DEF

2) Diese many-to-many ist eine geordnete Liste. Jede USER_ELECTRONIC_ID hat eine priorisierte Liste von ELECTRONICS_DEF_IDs. Zum Beispiel habe ich ein IPhone, ein IPad, ein Handy, und ich rangiere sie in der Reihenfolge, wie sehr ich sie mag.Um dies zu erreichen, ich USER_ELEC_PRIORITY_MAP Tisch haben, sieht das wie folgt aus -

USER_ELEC_IDELEC_DEF_IDPRIORITY

1IPAD1
1IPHONE2
1CELL3

USER_ELEC_ID und ELEC_DEF_ID sind PFKs. PRIORITÄT ist zusammengesetztes FK.

3) Wenn ich die Tabelle in Bezug auf meine Vorlieben (Mein neues IPad2 ist oben auf der Liste reoder mag, und iPad bewegt bis # 4), muß ich Teil des Composite-FK (Priorität) aktualisieren.