2009-11-17 6 views
2

J'essaie de mapper une collection (de type map) en utilisant une clé étrangère et une valeur fixe comme arguments key/mapping.Collection de cartes Hibernate avec clé constante

J'ai plusieurs tables de types de produits et une table de langue qui contient des choses comme des noms de produits et ainsi de suite.

Disons maintenant que nous avons une table d'accessoires qui contient (évidemment) des accessoires, alors le nom d'un accessoire est stocké dans la table de langue avec language.id = accessory.id et language.type = 'accessory'. La clé de la carte doit être le champ language.lang, une chaîne de code de langue. Maintenant, peu importe ce que j'ai essayé, je ne peux pas obtenir la partie "language.type = 'accessory'" juste, n'aime pas l'élément clé multiple, ce qui à son tour ne permettrait pas les éléments de toute façon .

J'ai aussi essayé avec un composant composite foreignKey, avec l'ensemble constant par défaut, mais cela n'a pas vraiment travailler soit:

<class name="AccessoryTypes" 
    table="accessorytypes"> 
    <id name="id" column="id" type="java.lang.Long" unsaved-value="0"> 
     <generator class="identity"></generator> 
    </id> 
    <map name="Name" table="ProductCode"> 
     <key column="CompositeId" /> 
     <map-key column="Language" type="string" /> 
     <one-to-many class="ProductCode" /> 
    </map> 
</class> 

<class name="Language" 
     table="Language"> 
     <composite-id name="compositeId" class="languageKey"> 
      <key-property name="Type"></key-property> 
      <key-property name="Id"></key-property> 
     </composite-id> 
     <property name="Lang" type="string"></property> 
     <property name="Value"></property> 
    </class> 

bien sûr avec les classes appropriées. Cette approche ne donne aucune erreur, mais ne remplit pas non plus la HashMap de la classe Accessory ...

toute aide serait appréciée, merci.

[modifier] maintenant je l'ai essayé avec property-ref comme ziodberg suggéré, d'abord avec un pas comme celui-ci:

<class name="AccessoryTypes" 
     table="accessorytypes"> 
    <id name="id" column="id" type="java.lang.Long" unsaved-value="0"> 
     <generator class="identity"></generator> 
    </id> 
    <properties name="CompositeId" > 
     <property name="id" /> 
     <property name="Type" formula="'accessory'" /> 
    </properties> 
    <map name="Name" table="ProductCode"> 
     <key property-ref="CompositeId" /> 
     <map-key column="Language" type="string" /> 
     <one-to-many class="ProductCode" /> 
    </map> 
</class> 

et

<class name="com.swissclick.wesco.web.model.ProductCode" 
     table="ProductCode"> 
    <composite-id class="com.swissclick.wesco.web.model.ProductCodeKey" mapped="true"> 
     <key-property name="Type"></key-property> 
     <key-property name="id"></key-property> 
    </composite-id> 
    <property name="Language" type="string"></property> 
    <property name="Value"></property> 
</class> 

mais cela ne fonctionne pas, soit, il donne

org.hibernate.MappingException: collection foreign key mapping has wrong number of columns: AccessoryTypes.Name type: component[Id,Type] 

ce qui ne donne aucune information utile sur google.

des idées?

+0

Serait-ce parce que dans votre collection votre référence à column = "compositeId" Que diriez-vous d'utiliser property-ref = "compositeId" à la place? – Zoidberg

Répondre

2

Édité. Donc, je ne suis toujours pas clair sur la structure de votre table - c'est ce qui m'a poussé quand j'ai écrit la réponse initiale.

Ma compréhension est que votre look quelque chose comme la table Language:

Id -- this is a PK of entity (e.g. Accessory) this entry provides localization info for 
Type -- string constant describing entity type (e.g. "accessory") 
Language -- language code 
Value -- actual localized string 

Est-ce que l'air à peu près juste? Si oui, cela pose la question sur la façon dont vous avez l'intention de localiser multiples champs au sein de la même entité. Ne devriez-vous pas au moins avoir une autre colonne liant au nom de propriété (champ)?

En tout cas, <formula> est en effet pas pris en charge dans le cadre du <key> (j'aurais juré qui est considérée) afin que vos options ici sont assez limitées:

  1. Utilisez un custom loader - c'est probablement le plus approche directe.
  2. Ajouter type comme une colonne réelle sur votre table Accessory et la carte comme une partie de id composite; vous pouvez ensuite mapper la carte Language en utilisant une clé composite. Ça devrait marcher mais c'est plutôt moche.
  3. Repensez votre approche. Avez-vous besoin vraiment besoin de charger une carte de langues à chaque fois? On dirait de le faire comme une requête séparée (ou même get() en supposant que l'ID composite approprié) pour le langage courant serait plus facile et (avec une configuration de mise en cache adéquate) beaucoup plus rapide.

Mise à jour précisiez 3 ci-dessus:

d'abord, permettez-moi de clarifier ce point - je suppose que vos chaînes localisées sont modifiables utilisateur lors de l'exécution. Si ce n'est pas le cas, je vous recommande fortement de renoncer complètement à la table et d'utiliser plutôt des bundles de ressources.

Je mapper Language comme une entité séparée avec type, id, language et (si vous avez besoin de faire cela pour plusieurs propriétés) property_name en tant que parties de id composite. La propriété localisable réelle sur votre entité (par exemple ProductName sur AccessoryType) serait transitoire. Vous pouvez ensuite charger manuellement la chaîne localisée appropriée pour votre entité en faisant quelque chose comme:

AccessoryType accessory = ...; 
Language language = (Language) session.get(Language.class, 
new LanguageKey("accessory", accessory.id, "en_US", "productName")); 
accessory.setProductName(language.getValue()); 

Vous pouvez même le faire dans le event listener en supposant que actuellement la langue choisie est globalement obtenue (via un appel local global ou fil) - il Cela se produira automatiquement par magie pour toutes vos entités. Si la table de langue est raisonnablement petite, vous pouvez avoir Hibernate cache it et vous n'encourrez même pas de hits de base de données sur ceci.

+0

c'était en fait la première chose que j'ai essayée, mais ça ne semble pas marcher dans Hibernate 3, l'élément clé ne prend pas un élément-formule. Donc, cela conduit à un "Le contenu de type d'élément" clé "doit correspondre" (colonne) * "." Erreur. – Zenon

+0

oui, c'est à quoi ressemble la table des langues. Eh bien, la performance n'est pas vraiment un problème (et je ne le serai jamais), alors je pensais que ce serait assez élégant si tous les objets de la base de données portent leurs différentes chaînes internationalisées avec eux (il n'y a que 3 langues). Je suppose que je vais probablement aller avec l'option 1., mais pourriez-vous élaborer 3.? Que voulez-vous dire par "direct get()"? Oh et merci d'avance pour vos efforts, ce problème m'a rendu fou au cours des derniers jours ... – Zenon

+0

merci beaucoup pour votre aide, je ne pense pas que je pourrais avoir compris cela de sitôt moi-même. C'est mon premier projet Java/Hibernate/Spring, après tout. Je serais allé avec des paquets de ressources tout de suite si le client n'avait pas demandé explicitement une base de données. La méthode get() avec l'écouteur d'événement sonne bien, un peu plus de travail maintenant mais beaucoup moins de travail à long terme. Je me demandais, y a-t-il un moyen de faire que les auditeurs d'événements n'écoutent que des événements concernant certaines classes (+ dérivées)? Je vais mettre à jour ma question avec ma solution une fois que j'ai terminé, si quelqu'un d'autre rencontre le même problème. – Zenon

Questions connexes