JPA / Hibernate – Incorporation d’un atsortingbut

Je ne parviens pas à mapper un atsortingbut incorporé d’une classe. J’ai créé des classes similaires à ce que j’essaie de faire pour illustrer. Fondamentalement, j’ai une hiérarchie de classes @Embeddable qui utilise l’inheritance. La classe de niveau supérieur “Numéro de pièce” n’a qu’un seul atsortingbut et les classes d’extension n’ajoutent aucun atsortingbut à la classe “Numéro de pièce”. Elles ajoutent seulement un peu de validation / logique.

Voici ce que je veux dire:

PARTIE

@Entity @Table(name="PART") public class Part { private Integer id; private Ssortingng name; private PartNumber partNumber; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="PART_NAME") public Ssortingng getName() { return name; } public void setName(Ssortingng name) { this.name = name; } @Embedded public PartNumber getPartNumber() { return partNumber; } public void setPartNumber(PartNumber partNumber) { this.partNumber = partNumber; } } 

NUMÉRO D’ARTICLE

 @Embeddable public abstract class PartNumber { protected Ssortingng partNumber; private Ssortingng generalPartNumber; private Ssortingng specificPartNumber; private PartNumber() { } public PartNumber(Ssortingng partNumber) { this.partNumber = partNumber; } @Column(name = "PART_NUMBER") public Ssortingng getPartNumber() { return partNumber; } public void setPartNumber(Ssortingng partNumber) { this.partNumber = partNumber; } /** * @param partNumber * @return */ public boolean validate(Ssortingng partNumber) { // do some validation return true; } /** * Returns the first half of the Part Number * * @return generalPartNumber */ @Transient public Ssortingng getGeneralPartNumber() { return generalPartNumber; } /** * Returns the last half of the Part Number * which is specific to each Car Brand * * @return specificPartNumber */ @Transient public Ssortingng getSpecificPartNumber() { return specificPartNumber; } } 

PARTENAIRE FORD

 public class FordPartNumber extends PartNumber { /** * Ford Part Number is formatted as 1234-#1234 * * @param partNumber */ public FordPartNumber(Ssortingng partNumber) { super(partNumber); validate(partNumber); } /* * (non-Javadoc) * * @see com.test.PartNumber#validate(java.lang.Ssortingng) */ @Override public boolean validate(Ssortingng partNumber) { // do some validation return true; } /* * (non-Javadoc) * * @see com.test.PartNumber#getGeneralPartNumber() */ @Override public Ssortingng getGeneralPartNumber() { return partNumber; } /* * (non-Javadoc) * * @see com.test.PartNumber#getSpecificPartNumber() */ @Override public Ssortingng getSpecificPartNumber() { return partNumber; } } 

CHEVY PARTNUMBER

 public class ChevyPartNumber extends PartNumber { /** * Chevy Part Number is formatted as 1234-$1234 * * @param partNumber */ public ChevyPartNumber(Ssortingng partNumber) { super(partNumber); validate(partNumber); } /* * (non-Javadoc) * * @see com.test.PartNumber#validate(java.lang.Ssortingng) */ @Override public boolean validate(Ssortingng partNumber) { // do some validation return true; } /* * (non-Javadoc) * * @see com.test.PartNumber#getGeneralPartNumber() */ @Override public Ssortingng getGeneralPartNumber() { return partNumber; } /* * (non-Javadoc) * * @see com.test.PartNumber#getSpecificPartNumber() */ @Override public Ssortingng getSpecificPartNumber() { return partNumber; } } 

Bien entendu, cela ne fonctionne pas, car Hibernate ignore la hiérarchie des inheritances et n’aime pas le fait que PartNumber soit abstrait. Existe-t-il un moyen de faire cela en utilisant JPA ou Hibernate Annotations? J’ai essayé d’utiliser l’annotation @Inheritance JPA.

Je ne suis pas en mesure de refactoriser la partie “Numéro de pièce” de la hiérarchie car le développeur d’origine souhaite pouvoir étendre le numéro de pièce avec N nombreuses classes XXXXPartNumber.

Est-ce que quelqu’un sait si quelque chose comme cela fera partie de JPA 2.0 ou d’une nouvelle version d’Hibernate?

L’inheritance de composant (par exemple, @Embeddable) n’est pas pris en charge et ne le sera probablement jamais. Il y a une bonne raison à cela: l’identifiant d’entité joue un rôle essentiel dans toutes les stratégies d’inheritance sockets en charge par Hibernate et les composants ne possèdent pas d’identifiants (mappés).

Vous avez trois choix:

A) Map PartNumber (et tous ses descendants) en tant qu’entités. PartNumber peut restr abstrait:

 @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="part_type", discriminatorType=DiscriminatorType.STRING) public abstract class PartNumber { ... } @Entity @DiscriminatorValue("Ford") public class FordPartNumber extends PartNumber { ... } 

B) D’après votre exemple, il semble que tous les descendants de PartNumber diffèrent uniquement par le comportement (ils n’introduisent aucune nouvelle propriété à stocker). Si c’est effectivement le cas, vous pouvez mapper les propriétés PartNumber avec votre propre valeur de discriminateur (afin de savoir quelle classe instancier) en tant que propriété privée @Embedded et disposer des accesseurs get / setPartNumber () dans les sous-classes appropriées de la classe Part marshall / unmarshall. Vous pouvez même écrire votre propre type personnalisé Hibernate pour le faire pour vous (c’est assez simple).

C) Si les descendants de PartNumber diffèrent par les propriétés qui doivent être stockées et que les mapper en tant qu’entités est inacceptable pour quelque raison que ce soit, vous pouvez utiliser marshall / unmarshall pour les convertir en chaîne (au format XML ou autre) et le stocker. J’utilise XStream dans ce but précis et j’ai écrit un type simple d’Hibernate pour l’accompagner. La cartographie de vos pièces ressemblerait à quelque chose comme

 @Type(type="xmlBean") public PartNumber getPartNumber() { return partNumber; } public void setPartNumber(PartNumber partNumber) { this.partNumber = partNumber; } 

et les descendants de PartNumber n’auront pas à être mappés du tout. L’inconvénient, bien sûr, est que le traitement de XML dans la firebase database est un peu plus compliqué, de sorte que ce n’est peut-être pas l’approche idéale pour quelque chose que vous auriez potentiellement besoin de faire rapport. OTOH, je l’utilise pour stocker les parameters de plug-in et cela m’a évité beaucoup de problèmes avec la maintenance des mappages / bases de données.

J’ai un problème similaire dans mon propre schéma et voici ce à quoi j’ai eu recours pour le moment:

Classe parentale:

 @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @SequenceGenerator(name="SEQ", sequenceName="part_id_seq", initialValue=1, allocationSize=1) public abstract class BasePart { @Id @Column(name="part_id") @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ") protected Long partId; @YourBusinessKeyAnnotation @Column(name="part_number") protected Ssortingng partNumber ... } 

Cours enfants:

 @Entity public class FordPart extends BasePart { ... } @Entity public class ChevyPart extends BasePart { ... } 

Je pouvais maintenant manipuler la clé biz comme il me fallait et cela fonctionnait bien car chaque type de pièce avait son propre tableau (ce qui est utile pour nous).

Vous pouvez également utiliser @Embedded avec @AtsortingbuteOverrides je pense, pour spécifier les noms de colonne différemment selon vos besoins … Il existe un exemple tiré de la documentation d’annotation .

 @Entity public class Person implements Serializable { // Persistent component using defaults Address homeAddress; @Embedded @AtsortingbuteOverrides( { @AtsortingbuteOverride(name="iso2", column = @Column(name="bornIso2") ), @AtsortingbuteOverride(name="name", column = @Column(name="bornCountryName") ) } ) Country bornIn; ... } 

 @Entity public class Person implements Serializable { // Persistent component using defaults Address homeAddress; @Embedded @AtsortingbuteOverrides( { @AtsortingbuteOverride(name="iso2", column = @Column(name="bornIso2") ), @AtsortingbuteOverride(name="name", column = @Column(name="bornCountryName") ) } ) Country bornIn; ... } 

 @Embedded @AtsortingbuteOverrides( { @AtsortingbuteOverride(name="city", column = @Column(name="fld_city") ), @AtsortingbuteOverride(name="nationality.iso2", column = @Column(name="nat_Iso2") ), @AtsortingbuteOverride(name="nationality.name", column = @Column(name="nat_CountryName") ) //nationality columns in homeAddress are overridden } ) Address homeAddress; 

Vous pourrez peut-être en abuser suffisamment pour ne pas vous en soucier …

Hmm, pas sûr. Avez-vous essayé de mettre @MappedSuperclasson PartNumber et @Embeddable sur les sous-classes. Voir aussi – https://forum.hibernate.org/viewtopic.php?t=966129

En tant que nœud latéral – avez-vous envisagé d’utiliser Hibernate Validator au lieu de la méthode de validation développée à la maison?

Ce que vous essayez de faire, c’est d’utiliser “l’inheritance intégrable”, ce que je ne crois pas supporte encore pour Hibernate.

 @Embeddable @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="partType", discriminatorType=DiscriminatorType.STRING) public PartNumber getPartNumber() { return partNumber; } 

Comme il semble que la valeur décroissante entre Ford et Chevy ressemble à un format. Je voudrais probablement masquer le mappage et append une fonction différente pour renvoyer le type spécifique que vous souhaitez.

 @Embeddable public PartNumber getPartNumber() { return partNumber; } @Transient public SpecificPartNumber getSpecificPartNumber() { return PartNumberFactory.create( getPartNumber() ); } 

Voir les liens dans les commentaires …

Comme il est mentionné dans d’autres réponses, il semble que Hibernate ne supporte pas l’inheritance des cartes incorporables (du moins, j’ai échoué à le faire fonctionner). J’ai trouvé quelques solutions de contournement (merci à ChssPly76 pour l’inspiration):

1) Remplacez @Embaddable par @Entity et stockez la hiérarchie PartNumber dans une table dédiée. Bien entendu, la relation @OneToOne doit être utilisée avec la classe composite ( Part ).

2) Introduisez une classe d’entités intermédiaire qui reflète pleinement la structure de la table de firebase database. Et mappez ensuite l’entité à vos classes de modèle de domaine (et inversement) manuellement. Cette approche offre une flexibilité extrême au prix du travail manuel pour écrire et tester le code de mappage.

3) Stockez les descendants PartNumber sous forme sérialisée et PartNumber appel à un sérialiseur qui doit pouvoir instancier la bonne classe lors de la désérialisation.

Pour ma tâche j’ai choisi la troisième approche. J’utilise Hibernate Types pour sérialiser des objects en JSON et stocker le résultat dans la colonne jsonb de PostgreSQL. Les types Hibernate utilisent Jackson sous le capot afin que toutes ses annotations (y compris celles qui contrôlent le comportement polymorphe) soient à votre disposition. Dans votre cas, le code serait comme ceci:

 @Entity public class Part { // ... @Type(type = "com.vladmihalcea.hibernate.type.json.JsonBinaryType") private PartNumber partNumber; } @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") @JsonSubTypes(value = [ JsonSubTypes.Type(value = FordPartNumber::class, name = "FordPartNumber"), JsonSubTypes.Type(value = ChevyPartNumber::class, name = "ChevyPartNumber") ]) public abstract class PartNumber { /* ... */ } public class FordPartNumber extends PartNumber { /* ... */ } public class ChevyPartNumber extends PartNumber { /* ... */ } 

Le JSON résultant dans la firebase database ressemblera à

 { "type": "FordPartNumber", // ... other serialized properties of the FordPartNumber class }