2010-06-17 3 views
3

J'ai une sous-classe et une superclasse. Cependant, seuls les champs de la superclasse doivent être conservés.Sous-classe Persist en tant que superclasse utilisant Hibernate

session.saveOrUpdate((Superclass) subclass); 

Si je fais ce qui précède, j'obtiendrai l'exception suivante.

org.hibernate.MappingException: Unknown entity: test.Superclass 
    at org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:628) 
    at org.hibernate.impl.SessionImpl.getEntityPersister(SessionImpl.java:1366) 
    at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:203) 
    at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:535) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:103) 
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) 
    at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:535) 
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:527) 
    at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:523) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:342) 
    at $Proxy54.saveOrUpdate(Unknown Source) 

Comment puis-je conserver une sous-classe en tant que superclasse? Je ne préfère pas créer une instance de superclasse, puis passer les valeurs de l'instance de la sous-classe. Parce que, il est facile d'oublier la mise à jour de la logique si des champs supplémentaires sont ajoutés à la superclasse dans le futur. Ce que vous essayez d'accomplir vous causera beaucoup de problèmes.

+0

Est-ce que 'Superclass' est réellement mappé? L'exception suggère que ce n'est pas le cas. –

+0

Oups, cela devrait être "org.hibernate.MappingException: Entité inconnue: test.Subclass". – franziga

Répondre

1

Imaginez ce qui se passe si vous chargez à nouveau les données. Quelle classe est censée utiliser Hibernate? La superclasse? Ou l'une des sous-classes? Laquelle?

Je suggère de mapper la superclasse directement, puis d'utiliser le delegate pattern pour implémenter la fonctionnalité étendue (en tournant essentiellement votre superclasse dans un objet de données qui est passé aux instances "worker").

+0

Je chargerai seulement les données à la superclasse seulement. Votre suggestion nécessite également de notifier une mise à jour de la délégation si la superclasse ajoute des champs supplémentaires. – franziga

0

Je suis également intéressé à trouver un moyen de le faire. Voici un cas motivant. Disons que j'ai un objet Utilisateur pour représenter un utilisateur dans mon application. L'objet User a une poignée de propriétés, comme le nom d'utilisateur, mot de passe, adresse e-mail, prénom, etc que je vais stocker dans une base de données. Lorsque je construis l'écran qui permet à un utilisateur de modifier son propre profil, je veux avoir une case à cocher pour "Changer le mot de passe", de sorte que je puisse afficher/masquer la boîte de mot de passe, et je veux aussi mot de passe "afin qu'ils ne le tapent pas. Je ne veux pas stocker ces propriétés dans la base de données et elles ne font pas vraiment partie de l'objet Utilisateur, donc je ne veux pas que ces champs existent dans l'utilisateur. Cependant, de nombreux frameworks Web facilitent la création d'une page de formulaire basée sur un objet en cours de modification.

La façon dont je voudrais résoudre ceci est de créer une sous-classe de User, appelons-la EditableUser, qui a quelques champs supplémentaires comme "changePassword" et "confirmPassword", et utilise cet objet sur mon formulaire. Mais le problème est que Hibernate ne saura pas comment enregistrer un objet EditableUser. (C'est aussi un problème de création d'un EditableUser à partir d'un utilisateur que vous chargez depuis la base de données, mais c'est faisable si vous avez un constructeur de copie)

La façon dont j'ai fini par contourner ce problème est d'utiliser la délégation : créez un objet EditableUser qui contient un utilisateur, ainsi que les propriétés supplémentaires que je ne veux pas enregistrer. Cela fonctionne raisonnablement bien, sauf que cela signifie que toutes mes données de liaison sur le formulaire doit changer pour accéder à l'objet utilisateur interne, donc il se sent mal à l'aise.

2

Il y a un type de solution à ce problème, et il est en fait couvert ici sur stackoverflow:

Hibernate/NHibernate : how to persist subclass as instance of superclass

Hibernate Documentation

Essentiellement, vous venez de dire Hibernate pour enregistrer votre classe comme la superclasse en utilisant un chaîne pour la superclasse comme:

session.save ("my.superclass", sous-classe);

Cela pourrait ne pas fonctionner dans tous les cas d'utilisation, mais pour moi, c'était juste le ticket.

Questions connexes