web-dev-qa-db-fra.com

Hibernate: Comment réparer "l'identifiant d'une instance modifiée de X à Y"?

org.hibernate.HibernateException: identifier of an instance 
of org.cometd.hibernate.User altered from 12 to 3

en fait, ma table user doit vraiment changer dynamiquement sa valeur, mon application Java est multithread . 

49
gennad

Modifiez-vous la valeur de la clé primaire d'un objet User quelque part? Tu ne devrais pas faire ça. Vérifiez que votre mappage pour la clé primaire est correct.

À quoi ressemble votre fichier XML de mappage ou vos annotations de mappage?

32
Juha Syrjälä

Vous devez détacher votre entité de la session avant de modifier ses champs d'identifiant

24
Danubian Sailor

Dans mon cas, le champ PK dans hbm.xml était de type "entier" mais dans le code de bean, il était long.

16
Muhammad Hewedy

Dans mon cas, je l'ai résolu en changeant le type de champ @Id de long à long.

4
Andres

Assurez-vous que vous n'essayez pas d'utiliser le même objet Utilisateur plus d'une fois lorsque vous modifiez l'ID. En d’autres termes, si vous faites quelque chose dans une opération de type batch:

User user = new User();  // Using the same one over and over, won't work
List<Customer> customers = fetchCustomersFromSomeService();
for(Customer customer : customers) {
 // User user = new User(); <-- This would work, you get a new one each time
 user.setId(customer.getId());
 user.setName(customer.getName());
 saveUserToDB(user);
}
3
Ken

Dans mon cas, les noms de sélecteurs et de sélecteurs étaient différents du nom de variable.

private Long stockId;
    public Long getStockID() {
        return stockId;
    }
    public void setStockID(Long stockID) {
        this.stockId = stockID;
    }

où il devrait être 

public Long getStockId() {
    return stockId;
}
public void setStockId(Long stockID) {
    this.stockId = stockID;
}

Dans mon cas particulier, cela était dû à une méthode dans mon implémentation de service qui nécessitait l'annotation de printemps @Transactional(readOnly = true). Une fois que j'ai ajouté cela, le problème a été résolu. Inhabituel cependant, c’était juste une déclaration choisie.

3
Ethereal

Dans mon cas, un modèle avait une faute de frappe, alors au lieu de vérifier l'équivalence (==), il utilisait une affectation égale (=).

J'ai donc changé la logique de template de:

if (user1.id = user2.id) ...

à 

if (user1.id == user2.id) ...

et maintenant tout va bien. Alors, vérifiez votre point de vue aussi!

3
nostromo

Je faisais face à ce problème aussi.

La table cible est une table de relations, reliant deux ID provenant de tables différentes. J'ai une contrainte UNIQUE sur la combinaison de valeurs, remplaçant la clé PK . Lors de la mise à jour d'une des valeurs d'un tuple, cette erreur s'est produite.

Voici à quoi ressemble la table (MySQL):

CREATE TABLE my_relation_table (
  mrt_left_id BIGINT NOT NULL,
  mrt_right_id BIGINT NOT NULL,
  UNIQUE KEY uix_my_relation_table (mrt_left_id, mrt_right_id),
  FOREIGN KEY (mrt_left_id)
    REFERENCES left_table(lef_id),
  FOREIGN KEY (mrt_right_id)
    REFERENCES right_table(rig_id)
);

La classe Entity pour l'entité RelationWithUnique ressemble en gros à ceci:

@Entity
@IdClass(RelationWithUnique.class)
@Table(name = "my_relation_table")
public class RelationWithUnique implements Serializable {

  ...

  @Id
  @ManyToOne
  @JoinColumn(name = "mrt_left_id", referencedColumnName = "left_table.lef_id")
  private LeftTableEntity leftId;

  @Id
  @ManyToOne
  @JoinColumn(name = "mrt_right_id", referencedColumnName = "right_table.rig_id")
  private RightTableEntity rightId;

  ...

Je l'ai réparé par

// usually, we need to detach the object as we are updating the PK
// (rightId being part of the UNIQUE constraint) => PK
// but this would produce a duplicate entry, 
// therefore, we simply delete the old Tuple and add the new one
final RelationWithUnique newRelation = new RelationWithUnique();
newRelation.setLeftId(oldRelation.getLeftId());
newRelation.setRightId(rightId);  // here, the value is updated actually
entityManager.remove(oldRelation);
entityManager.persist(newRelation);

Merci beaucoup pour le soupçon de PK, je viens juste de le manquer.

2
bully

Le problème peut également se trouver dans différents types de PK d'objet ("Utilisateur" dans votre cas) et tapez vous demandez à Hibernate d'obtenir session.get(type, id);.

Dans mon cas, l'erreur était identifier of an instance of <skipped> was altered from 16 to 32. Le type de PK de l’objet était Integer, hibernate a été interrogé pour le type Long.

1
Oleg Poltoratskii

C'est une vieille question, mais je vais ajouter le correctif pour mon problème particulier (Spring Boot, JPA utilisant Hibernate, SQL Server 2014) car il ne correspond pas exactement aux autres réponses incluses ici:

J'ai eu une clé étrangère, par exemple my_id = '12345', mais la valeur dans la colonne référencée était my_id = '12345'. Il y avait unespace supplémentaireà la fin que hibernate n'aimait pas. J'ai supprimé l'espace, corrigé la partie de mon code qui permettait cet espace supplémentaire et tout fonctionne correctement. 

0
Erik Pearson

Face au même problème ... J'ai eu une assosciation entre 2 haricots. Dans le haricot A, j'avais défini le type de variable comme Integer et dans le haricot B, j'avais défini la même variable que Long. Je les ai changés tous les deux en Integer. Cela a résolu mon problème. 

0
HARSH KHATRI

C'est un problème dans votre méthode de mise à jour. Il suffit d’introduire un nouvel utilisateur avant d’enregistrer les modifications et tout ira bien. Si vous utilisez le mappage entre DTO et la classe Entity, faites-le avant le mappage.

J'ai eu cette erreur aussi. J'avais objet utilisateur, essayant de changer son emplacement, l'emplacement était FK dans la table utilisateur. J'ai résolu ce problème avec

@Transactional
public void update(User input) throws Exception {

    User userDB = userRepository.findById(input.getUserId()).orElse(null);
    userDB.setLocation(new Location());
    userMapper.updateEntityFromDto(input, userDB);

    User user= userRepository.save(userDB);
}  
0
I.R.1989

Dans mon cas, c'était parce que la propriété était longue sur object mais int dans le mappage xml, cette exception devrait être plus claire.

0
KgaboL