Comment mélanger les stratégies d'héritage avec les annotations JPA et L'hibernation?

Selon Documentation De Référence Sur L'Hibernation il devrait être possible de mélanger différentes stratégies de cartographie des héritages en utilisant les XML-Metadata:

http://docs.jboss.org/hibernate/stable/core/reference/en/html/inheritance.html#inheritance-mixing-tableperclass-tablepersubclass

cependant, la section correspondante de la Hibernation Annotations Guide De Référence ne couvre pas que:

http://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity.html#d0e1168

d'un autre côté, les JavaDocs suggèrent que les stratégies de mélange héréditaire devraient être possibles. Par exemple, dans javax.persistance.DiscriminatorColumn il dit:

La stratégie et de la colonne discriminante sont spécifiés dans la racine d'une classe d'entité hiérarchie ou la subhiérarchie dans laquelle une stratégie d'héritage différente est appliquée.


ce qui suit est un exemple pour la cartographie que j'essaie de réaliser. Je voudrais utiliser tableau par sous-classe cartographie près de la racine de la hiérarchie, mais le changement d' table par classe de la hiérarchie cartographie près des feuilles. Voici un exemple de code:

@Entity
@Inheritance( strategy = InheritanceType.JOINED )
public abstract class A implements Serializable
{
    @Id
    private String id;

    // other mapped properties...
}

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
public class BB extends A
{
    // other mapped properties and associations...
}

@Entity
public class BB1 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
public class BB2 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
public class CC extends A
{
    // other mapped properties and associations...
}

@Entity
public class CC1 extends CC
{
    // other stuff, not necessarily mapped...
}

...

Ce que j'attends de cette cartographie est d'avoir exactement 3 tables: A, BB et CC. Les deux BB et CC devrait avoir une colonne discriminante par défaut appelée DTYPE. Ils doivent également fournir toutes les colonnes nécessaires pour toutes les propriétés cartographiées et les associations de leurs sous-classes respectives.

a la place, la hiérarchie de classe semble utiliser le tableau par sous-classe stratégie d'héritage tout au long. I. e. J'obtiens un tableau pour chacune des entités mentionnées ci-dessus. Je voudrais éviter cela, puisque les feuilles de la hiérarchie de classe sont extrêmement légers et il semble juste exagéré d'avoir une table séparée pour chacun d'eux!


ai-je négligé quelque chose? Tout conseil est très apprécié! Je serai heureux de fournir des informations supplémentaires...

30
demandé sur Meeque 2010-10-12 17:10:13

2 réponses

selon la Documentation de référence sur L'hibernation, il devrait être possible de mélanger différentes stratégies de cartographie des héritages en utilisant les Métadonnées XML de L'hibernation (...)

en Fait, ce n'est pas vraiment pris en charge, ils "trichent" en utilisant une table secondaire pour passer de la stratégie de table simple dans l'exemple de la documentation. Citing Java Persistance avec Hibernate:

vous pouvez cartographier l'ensemble héritage hiérarchies par nichage <union-subclass>, <sub- class>, et <joined-subclass> cartographie élément. Vous ne pouvez pas mélanger - pour exemple, pour passer d'un tableau-hiérarchie par classe avec un discriminateur normalisé table par sous-classe de la stratégie. une Fois vous avez pris une décision pour une l'héritage de stratégie, vous devez s'en tenir à elle.

Ce n'est pas tout à fait vrai, cependant. Avec quelques trucs D'hibernation, vous pouvez changer la stratégie de cartographie pour un particulier sous-classe. Par exemple, vous pouvez mapper une hiérarchie de classe à un seul tableau, mais pour une sous-classe particulière, passer à une table séparée avec un stratégie de cartographie des clés étrangères, comme avec une table par sous-classe. C'est possible avec l' <join> cartographie élément:

<hibernate-mapping>
  <class name="BillingDetails"
      table="BILLING_DETAILS">

    <id>...</id>

    <discriminator
        column="BILLING_DETAILS_TYPE"
        type="string"/>
    ...
    <subclass
        name="CreditCard"
        discriminator-value="CC">
      <join table="CREDIT_CARD">
        <key column="CREDIT_CARD_ID"/>

        <property name="number" column="CC_NUMBER"/>
        <property name="expMonth" column="CC_EXP_MONTH"/>
        <property name="expYear" column="CC_EXP_YEAR"/>
        ...
      </join>
    </subclass>

    <subclass
        name="BankAccount"
        discriminator-value="BA">
      <property name=account" column="BA_ACCOUNT"/>
      ...
    </subclass>
  ...
  </class>
</hibernate-mapping>

Et vous pourriez obtenir le même avec des annotations:

Java Persistence supporte également cette stratégie de cartographie des héritages mixtes avec annotations. La carte superclasse BillingDetailsInheritanceType.SINGLE_TABLE, comme vous l'avez fait avant. Maintenant, mappez la sous-classe que vous voulez séparer de la table simple à une table secondaire.

@Entity
@DiscriminatorValue("CC")
@SecondaryTable(
    name = "CREDIT_CARD",
    pkJoinColumns = @PrimaryKeyJoinColumn(name = "CREDIT_CARD_ID")
)
public class CreditCard extends BillingDetails {
    @Column(table = "CREDIT_CARD",
        name = "CC_NUMBER",
        nullable = false)
    private String number;
    ...
}

je n'ai pas tester, mais vous pourriez peut-être essayer:

  • Une carte à l'aide d'un SINGLE_TABLE stratégie
  • carte BB, CC, etc à l'aide de la @SecondaryTable annotation.

Je ne l'ai pas testé, Je ne sais pas si ça marchera bien pour BB1, BB2.

Référence

  • persistance de Java avec hibernation
    • 5.1.5 stratégies de mélange des héritages (p207-p210)
27
répondu Pascal Thivent 2010-10-12 16:40:31

juste pour la clarté, voici la solution de Pascal appliquée au code exemple de ma question:

@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
@DiscriminatorColumn( name = "entityType", 
        discriminatorType = DiscriminatorType.STRING )
public abstract class A implements Serializable
{
    @Id
    private String id;

    // other mapped properties...
}

@Entity
@SecondaryTable( name = "BB" )
public class BB extends A
{
    @Basic( optional = false)
    @Column( table = "BB" )
    private String property1;

    // other mapped properties and associations...
}

@Entity
public class BB1 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
public class BB2 extends BB
{
    // other stuff, not necessarily mapped...
}

@Entity
@SecondaryTable( name = "CC" )
public class CC extends A
{
    @ManyToOne( optional = false)
    @JoinColumn( table = "CC" )
    private SomeEntity association1;

    // other mapped properties and associations...
}

@Entity
public class CC1 extends CC
{
    // other stuff, not necessarily mapped...
}

...

j'ai appliqué avec succès cette approche à mon problème, et je vais m'y tenir pour le moment. Cependant, je vois encore les inconvénients suivants:

  • la colonne discriminante est située dans la table principale pour la hiérarchie, la table pour la racine-énité A. Dans mon cas, il suffirait que la colonne discriminante les tableaux secondaires BB et CC.

  • Quand on ajoute des propriétés et des associations de sous-classes de BB ou CC, il/elle doit préciser qu'ils doivent être mappées à la table secondaire. Ce serait bien, s'il y avait un moyen d'en faire la valeur par défaut.

24
répondu Meeque 2010-10-13 19:50:51