2010-10-23 66 views
1

Je classe d'entité annotée JPA comme:problème généré automatiquement primary_key utilisant JPA sur DerbyDB

@Configurable 
@Entity 
@Table(name="PLAYERS") 
public class Player 
{ 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name="ID") 
    private Integer id; 
    @Column(name="NAME") 
    private String name; 

    @PersistenceContext 
     public transient EntityManager entityManager; 

    ... 
} 

Cela a bien fonctionné jusqu'à ce que je décide de créer la table avec des données Backupées YAML en utilisant la syntaxe comme:

createNativeQuery("INSERT INTO PLAYERS ...") 

Après la création réussie lorsque je tente de créer une entité avec:

Player player = new Player(); 
player.setName("new player"); 
player.persist(); 

je suis arrivé erreur:

SQL Error: -1, SQLState: 23505 

en rapport avec le chevauchement des primary_keys, parce identifiant généré pour une nouvelle entité = 1 (la même que la ligne de données récupéré depuis Backupées). Bien sûr, je peux récupérer les données du fichier de sauvegarde en utilisant la syntaxe jpa/java mais dans ce cas, je n'ai aucun contrôle sur les clés primaires des données insérées, etc. Comment résoudre ce problème? Est-il possible de mettre à jour id_generator après l'insertion de données sauvegardées?

Répondre

2

Parce que vous avez inséré des données manuellement, vous devez modifier la table pour changer la valeur de départ de la colonne d'identité:

ALTER TABLE PLAYERS ALTER COLUMN ID RESTART WITH 1234; 

Où 1234 est l'ID maximum de vos données de sauvegarde.

Plus de détails dans la documentation du ALTER TABLE statement:

RESTART WITH integer-constant specifies the next value to be generated for the identity column. RESTART WITH is useful for a table that has an identity column that was defined as GENERATED BY DEFAULT and that has a unique key defined on that identity column. Because GENERATED BY DEFAULT allows both manual inserts and system generated values, it is possible that manually inserted values can conflict with system generated values. To work around such conflicts, use the RESTART WITH syntax to specify the next value that will be generated for the identity column. Consider the following example, which involves a combination of automatically generated data and manually inserted data:

CREATE TABLE tauto(i INT GENERATED BY DEFAULT AS IDENTITY, k INT) 
CREATE UNIQUE INDEX tautoInd ON tauto(i) 
INSERT INTO tauto(k) values 1,2

The system will automatically generate values for the identity column.?? But now you need to manually insert some data into the identity column:

INSERT INTO tauto VALUES (3,3) 
INSERT INTO tauto VALUES (4,4) 
INSERT INTO tauto VALUES (5,5)

The identity column has used values 1 through 5 at this point.?? If you now want the system to generate a value, the system will generate a 3, which will result in a unique key exception because the value 3 has already been manually inserted.????To compensate for the manual inserts, issue an ALTER TABLE statement for the identity column with RESTART WITH 6:

ALTER TABLE tauto ALTER COLUMN i RESTART WITH 6
+0

C'est exactement ce que je voulais, fonctionne comme vous le souhaitez. Une autre solution possible que j'ai découverte est: pour modifier le champ AUTOINCREMENTVALUE dans la table SYS.SYSCOLUMNS, que DerbyDb utilise pour stocker la dernière valeur générée pour primary_key mais parce que c'est une table système, des privilèges d'administrateur sont requis. Donc, c'est une solution plus gênante. – user85005

+0

@ user85005: Oui, cela fonctionnerait aussi (mais nécessitera plus de privilèges que vous avez remarqué). En fait, l'alter se traduira par une modification des tables système. C'est juste plus pratique d'utiliser l'alter IMO. –