2010-10-01 12 views
1

J'ai un sac dont la structure ressemble à ceci:sac Mise en veille prolongée avec plusieurs éléments

<bag name="foo" fetch="select" table="table_of_foos"> 
    <key column="foo_ids"/> 
    <many-to-many class="Bar" column="bar_ids"/> 
</bag> 

Ma table « table_of_foos » a deux colonnes: « foo_ids » et « bar_ids », dont aucun est unique. Je veux ajouter une autre colonne à cette table qui contient des informations sur la relation des foos aux barres, de sorte que ma table contienne trois colonnes. Ensuite, je veux être en mesure d'accéder à cette information dans ma webapp. Malheureusement, il ne semble pas que je puisse ajouter une propriété ou un élément dans le sac. Ce que je veux faire est quelque chose comme ceci:

<bag name="foo" fetch="select" table="table_of_foos"> 
    <key column="foo_ids"/> 
    <many-to-many class="Bar" column="bar_ids"/> 
    <element column="still_valid" type="integer"/> 
</bag> 

Quelle est la meilleure façon d'accomplir ceci?

Répondre

3

Si votre table jointe a besoin d'une colonne supplémentaire autre que sa clé primaire (composite), , vous devez implémenter une classe jointe supplémentaire.

public class Foo { 

    Collection<FooBar> bar = new ArrayList<FooBar>(); 

} 

public class Bar { 

    Collection<FooBar> foo = new ArrayList<FooBar>(); 

} 

La classe rejoint (qui a besoin d'une clé primaire composite - mis en œuvre en tant que classe interne statique) est décrit comme suit

public class FooBar { 

    private FooBarId fooBarId; 

    private String additionalProperty; 

    public static class FooBarId implements Serializable { 

     private Integer fooId; 
     private Integer barId; 

     private Foo foo; 
     private Bar bar; 

     // getter's and setter's 

     public FooBarId() {} 
     public FooBarId(Integer fooId, Integer barId) { 
      this.fooId = fooId; 
      this.barId = barId; 
     } 

     public boolean equals(Object o) { 
      if(!(o instanceof FooBarId)) 
       return false; 

      FooBarId other = (FooBarId) o; 
      return new EqualsBuilder() 
         .append(getFooId(), other.getFooId()) 
         .append(getBarId(), other.getBarId()) 
         .isEquals(); 
     } 

     public int hashCode() { 
      return new HashCodeBuilder() 
         .append(getFooId()) 
         .append(getBarId()) 
         .hashCode(); 
     } 

    } 

} 

re-écrire votre mapping comme

/* Foo.class */ 

<bag name="bar" table="table_of_foos"> 
    <key column="BAR_ID" insert="false" update="false"/> 
    <one-to-many class="FooBar" table="table_of_foos"/> 
</bag> 

/* Bar.class */ 

<bag name="foo" table="table_of_foos"> 
    <key column="FOO_ID" insert="false" update="false"/> 
    <one-to-many class="FooBar" table="table_of_foos"/> 
</bag> 

Et FooBar mappage

<class name="FooBar"> 
    <composite-id name="fooBarId" class="FooBar$FooBarId"> 
     <key-property name="fooId" column="FOO_ID"/> 
     <key-property name="barId" column="BAR_ID"/> 
    </composite-id> 
    <property name="additionalProperty" type="string"/> 
    <many-to-one name="foo" column="FOO_ID" class="Foo" insert="false" update="false"/> 
    <many-to-one name="bar" column="BAR_ID" class="Bar" insert="false" update="false"/> 
</class> 

Si vous le souhaitez, vous pouvez également mapper un élément composite au lieu d'une classe jointe (un élément de composant n'a pas besoin de clé primaire (composite) et a son cycle de vie lié à celui de son instance d'entité propriétaire. Gardez cela à l'esprit)

vous Créer élément composite (maintenant sans identifiant)

public class FooBar { 

    private String additionalProperty; 

    private Foo foo; 
    private Bar bar; 

} 

et définir le mapping suivant

/* Foo.class */ 

<bag name="bar" table="table_of_foos"> 
    <key column="BAR_ID"/> 
    <composite-element class="FooBar"> 
     <property name="additionalProperty" type="string"/> 
     <many-to-one name="foo" column="FOO_ID" class="Foo" insert="false" update="false"/> 
     <many-to-one name="bar" column="BAR_ID" class="Bar"/> 
    </composite-element> 
</bag> 

/* Bar.class */ 

<bag name="foo" table="table_of_foos"> 
    <key column="FOO_ID"/> 
    <composite-element class="FooBar"> 
     <property name="additionalProperty" type="string"/> 
     <many-to-one name="foo" column="FOO_ID" class="Foo" insert="false" update="false"/> 
     <many-to-one name="bar" column="BAR_ID" class="Bar"/> 
    </composite-element> 
</bag> 
+0

Merci, c'était très utile! – denaje

+1

+1 pour cette réponse agréable et détaillée –

0

Je n'ai pas pu obtenir ces mapping travailler par écrit par Arthur Ronald F D Garcia. Ce code n'a pas fonctionné et a abouti à une exception MappingException.

Tentative non valide

<set name="StoreDepartments" table="`ou_store_org_unit`"> 
    <key column="`ou_id`" /> 
    <composite-element class="NHibernate.Map.OrganizationUnit+StoreDepartment+Relation, CentralDataLayer"> 
     <property name="Id" column="`ou_store_id`" type="Int32" /> 
     <many-to-one name="OrganizationUnit" column="`ou_id`" class="NHibernate.Map.OrganizationUnit, CentralDataLayer" /> 
     <many-to-one name="StoreDepartment" column="`store_ou_id`" class="NHibernate.Map.OrganizationUnit+StoreDepartment, CentralDataLayer" /> 
    </composite-element> 
</set> 

Resulting Error: Repeated column in mapping for collection: 
NHibernate.Map.OrganizationUnit.StoreDepartments column: ou_id 

j'ai pu le faire fonctionner avec ce qui suit.

Tentative valable

<set name="StoreDepartments" table="`ou_store_org_unit`"> 
    <key column="`ou_id`" /> 
    <composite-element class="NHibernate.Map.OrganizationUnit+StoreDepartment+Relation"> 
     <parent name="OrganizationUnit" /> 
     <property name="Id" column="`ou_store_id`" type="Int32" /> 
     <many-to-one name="StoreDepartment" column="`store_ou_id`" class="NHibernate.Map.OrganizationUnit+StoreDepartment" /> 
    </composite-element> 
</set> 

De plus:

Si NHibernate essaie de mettre à jour votre jeu, même si vous ne modifiez pas, essayez les méthodes remplaçant GetHasCode et Equals. Plus information here.