6

Nous avons une base de données héritée que nous ne pouvons pas modifier. Et nous essayons de passer à la NHibernate au lieu de l'ancienne couche DataAccess qui est une poubelle et qui est trop lente.NHibernate navigateurs mappés à la partie d'un problème de clé composite - utilisation de la base de données existante

il a des tables comme celles-ci:

Table GPI a (PU_ID, PAR_ID, données, Data2) colonnes
table BLOC a (GA_ID, données, PAR_ID) colonnes
table COMPANY a (PU_ID, données) colonnes

j'avais créé ces correspondances pour les tableaux ci-dessus:

GPI

<class name="GroupPartnerInterest" table="[GPI]"> 
    <composite-id > 
     <key-property name="GroupId" column="PAR_ID" /> 
     <key-property name="CompanyId" column="PU_ID" /> 
    </composite-id> 
    <property name="data" column="Data"/> 
    <property name="data2" column="Data2"/> 
    <many-to-one name="Company" fetch="select" cascade="none"> 
     <column name="PU_ID"/> 
    </many-to-one> 
    <set name="Blocks" cascade="none" inverse="true" fetch="select"> 
     <key property-ref="GroupId"> 
      <column name="PAR_ID"/> 
     </key> 
     <one-to-many class="Block"/> 
    </set> 
</class> 

BLOC

<class name="Block" table="[BLOCK]" > 
    <id name="BlockId" column="GA_ID" > 
     <generator class="assigned"/> 
    </id> 
    <property name="data" column="Data"/> 
    <property name="GroupId" column="PAR_ID"/> 
    <set name="GroupPartnerInterests" cascade="all-delete-orphan" fetch="select"> 
     <key property-ref="GroupId"> 
      <column name="PAR_ID"/> 
     </key> 
     <one-to-many class="GroupPartnerInterest"/> 
    </set> 
</class> 

COMPANY

<class name="Company" table="[COMPANY]"> 
    <id name="CompanyId" column="PU_ID"> 
     <generator class="assigned"/> 
    </id> 
    <property name="data" column="Data"/> 
    <set name="GroupPartnerInterests" cascade="none" inverse="true" fetch="select"> 
     <key> 
      <column name="PU_ID"/> 
     </key> 
     <one-to-many class="GroupPartnerInterest"/> 
    </set> 
</class> 

Les classes sont très simple et clair. Tous implémentent les méthodes Equals et GetHashCode.

Voici la liste des navigateurs qui fonctionnent:

  • GroupPartnerInterest.Company - fonctionne très bien
  • Company.GroupPartnerInterests - fonctionne très bien
  • GroupPartnerInterest.Company - fonctionne très bien

Et ces deux échouent:

  • Block.GroupPartnerInterests:

J'ai une unité test:

[TestMethod] 
public void TestGroupPartnerInterests() 
{ 
    using (ISession session = SessionFactory.OpenSession()) 
    { 
     IList<Block> blocks = session.CreateCriteria(typeof(Block)) 
      .SetMaxResults(5).List<Block>(); 

     foreach (var block in blocks) 
     { 
      TestContext.WriteLine("Block #{0}", block.BlockId); 

      if (block.GroupPartnerInterests != null) 
      { 
       foreach (GroupPartnerInterest gpi in block.GroupPartnerInterests) 
       { 
        TestContext.WriteLine("Company '{0}':", gpi.Company.CompanyId); 
       } 
      } 
     } 
    } 
} 

Si je commente sur la cartographie de navigation blocs dans les travaux d'essai de cartographie GPI et sorties des données:

Block #1
Company 'LALA':
Company 'LALA SA':
Block #2
Company 'BG PO':
Company 'LIMPOPO':
Block #3
Company 'HAHA':
Company 'Other partner(s)':
Block #4

Mais le test échoue avec l'erreur suivante:

NHibernate.LazyInitializationException: Initializing[Model.EntityClasses.Block#999]-failed to lazily initialize a collection of role: Model.EntityClasses.Block.GroupPartnerInterests, no session or session was closed.

Le '999' est PAR_ID existant - les données sont cohérentes: il y a deux blocs avec ce PAR_ID et quelques enregistrements dans GPI. Pourquoi cela ferme-t-il la session à un moment donné?

  • GroupPartnerInterest.Blocks:

Le test unitaire est presque le même que je l'ai mentionné ci-dessus, les propriétés seulement différentes sont utilisées. Une erreur est ci-dessous:

NHibernate.MappingException: NHibernate.MappingException: property not found: GroupId on entity Model.EntityClasses.GroupPartnerInterest.

Si je retire "property-ref = GroupId" de l'élément du navigateur blocs dans la cartographie GPI, je vais faire l'exception suivante:

NHibernate.FKUnmatchingColumnsException: NHibernate.FKUnmatchingColumnsException: Foreign key (FKA3966498349694F:[BLOCK] [PAR_ID])) must have same number of columns as the referenced primary key ([GPI] [PAR_ID, PU_ID]).

Est Y at-il un moyen de mapper les Blocs à GPI pour que le navigateur GroupPartnerInterest.Blocks fonctionne?

Merci, Alex

Répondre

2

Le problème est le suivant:

  • Si vous avez une entité avec un identifiant composite , toutes les références à elle doit maintenir l'identifiant composite, donc il doit être deux clés étrangères.
  • Les blocs dans GroupPartnerInterest étant un ensemble, la clé étrangère est dans Blocks, pointant sur GroupPartnerInterest. Cela nécessiterait deux clés étrangères, qui ne sont pas disponibles.
  • property-ref est de remplacer la clé primaire par une autre propriété. Il s'agit donc d'une propriété de la table d'un côté de la relation, qui est GroupPartnerInterest, mais il n'y a pas de GroupId.
  • Vous pouvez probablement utiliser property-ref pour GroupPartnerInterest.Blocks (parce que les deux clés étrangères manquent, pour faire le point Block.PAR_ID à GPI.PAR_ID), mais je pense à deux fois.

Je ne peux pas vous donner une solution de travail ici. Je n'utilise pas de touches composites et c'est plus complexe. Mais il y a d'autres pensées:

  • Je voudrais essayer d'éviter la clé composite. Si ce n'est pas possible, écrivez une classe qui représente la clé composite. Cela le rend beaucoup plus facile à gérer.
  • Je voudrais essayer d'éviter les relations qui ne sont pas basées sur la clé primaire. Il peut y avoir des raisons de faire autrement, NH les soutient, je pense juste qu'ils causent des problèmes.

Pourquoi la session fermée? Je ne sais pas, je voudrais jeter un oeil à la trace de la pile. C'est l'exception vraiment lancée depuis le bloc using? Ou est-il lancé à partir d'une méthode TestCleanup?

+0

Merci pour la réponse en profondeur! Je vais essayer de convaincre notre équipe de modifier un peu le schéma DB: ajoutez une clé primaire autogénérée (incrémentation) à la table GPI. Cela va résoudre le problème de propriété-ref = GroupId et devrait résoudre mes problèmes de navigation – LucID

+0

J'ai un problème très similaire. J'ai essayé de mapper ce scénario avec des mappages XML et fluides, mais pas de joie. Malheureusement, je ne peux pas changer le schéma pour le moment. Puis-je vous aider à jeter un coup d'œil? http://stackoverflow.com/questions/25191275/fluent-nhibernate-map-hasmany-to-entity-table-with-no-primary-key –