J'utilise Hibernate comme couche de persistance. Il existe 2 entités qui vivent dans la même table extension d'une superclasse avec une stratégie d'héritage de table unique.
org.hibernate.PersistentObjectException: detached entity passed to persist: C
5 Réponses :
Dans ce cas, "C" est un objet que la session hibernate ne sait rien, mais il a un identifiant, il suppose donc que l'objet a déjà été persisté. Dans ce contexte, persist () n'a aucun sens, et il échoue donc. P>
Le Javadoc pour hibernate session.persist () (Je sais que vous n'utilisez pas l'API hibernate, mais la sémantique est la même, et les documents hibernés sont meilleurs) dit "faire une instance transitoire persistante". Si votre objet a déjà un identifiant, ce n'est pas transitoire. Au lieu de cela, il pense que c'est une instance détachée (c'est-à-dire une instance qui a été persistée, mais n'est pas associée à la session en cours). P>
Je vous suggère d'essayer de fusionner () au lieu de persister (). P>
Merci d'avoir expliqué la raison de l'exception, j'y dérangerai. La fusion n'a pas échoué, mais donne un nouvel identifiant, ignorant ce qui a été défini.
Vous pouvez utiliser votre propre identifiant (non généré) et procéder à ce qui suit: p>
De cette façon, vous effacerez l'identifiant de la table avant de la réinsérer comme c. P>
Ce serait assez difficile à mettre en œuvre. Toutes mes entités utilisent des identifiants auto-interprétés. Existe-t-il un moyen de forcer la valeur d'un identifiant généré?
Comment faites-vous la distinction entre les deux entités de la table? Je suppose qu'il y a une valeur de champ (ou des valeurs) que vous pouvez changer pour faire B dans un C? P>
Vous pouvez avoir une méthode où vous chargez la super-classe A et modifier les valeurs distinctives et enregistrer. Ensuite, dans votre prochaine session hibernate, votre B sera un c. P>
Hibernate utilise une colonne discriminatoire pour déterminer quelle classe il doit instancier lors du chargement des données. La valeur de la colonne est égale au nom simple de la classe. Vous suggérez-vous d'utiliser SQLL SQLL pour modifier les données de la table? Je ne vois pas une autre façon de faire ce que vous suggérez.
Je pense que Skaffman est juste ici, une fois que l'identifiant a été défini, il ne persiste pas et que l'ID est généré, il s'attend à ce que la séquence soit chargée de l'attribution du numéro d'identification. P>
Vous ne pouvez éventuellement pas mettre l'identifiant comme @GeneratedValue? ou l'un des différents types de stratégie génératrice peut-être éviter la fusion générant une nouvelle valeur de séquence, mais je soupçonne que cela serait problématique. P>
Hibernate tente de rendre la persistance aussi transparente que possible, ce qui signifie qu'il essaie de suivre les mêmes principes que les objets Java normaux. Maintenant, reformulez votre question en Java, vous obtiendrez: P>
Comment puis-je convertir une instance de classe B en une instance de classe C (incompatible) C? p> blockQuote>
Et vous connaissez la réponse à cela - vous ne pouvez pas. Vous pouvez créer une nouvelle instance forte> nouvelle forte> de C et copier les attributs nécessaires, mais b sera toujours em> Be B, jamais C. Ainsi, la réponse à votre question initiale est - elle ne peut pas être faite via l'API JPA ou Hibernate. P>
Cependant, contrairement à Java uni, avec hibernate, vous pouvez tricher :-)
inheritanceType.single_table_table code> est mappé en utilisant
@discriminatorcolumn code> et afin de convertir B en C, vous devez Mettez à jour sa valeur de tout ce qui est spécifié pour B dans tout ce qui est spécifié pour C. L'astuce est - vous ne pouvez pas le faire en utilisant l'API Hibernate; Vous devez le faire via SQL plaine. Vous pouvez toutefois planter cette instruction de mise à jour comme requête nommée SQL et l'exécuter à l'aide d'installations Hibernate. P>
L'algorithme est donc: p>
expulsion forte> B de la session si elle est là (c'est important) li> - Exécutez votre requête nommée. LI>
- Chargez ce qui est-maintenant-connu-connais-c utilisant l'ID de l'ancien B. LI>
- Attributs de mise à jour / SET si nécessaire. LI>
- persist C li> ol>
J'ai ajouté l'exception à la question
Juste un hunch, mais avez-vous essayé d'appeler fusionné () au lieu de persister ()?
Ouais, la fusion donne C un nouvel identifiant.
Cela peut être un exemple de l'insuffisance de l'API d'EntityManager. Ce n'est pas aussi expressif que l'API d'hibernation indigène et fait parfois un peu moins de sens.
Y a-t-il un moyen de le faire dans l'API d'Hibernate indigène?