2010-05-19 9 views
3

Dans mon projet j'utilise NHibernate/FluentNHibernate, et je travaille avec deux entités, contrats et services.nhibernate/fluenthibernate throws StackOverflowException

Ceci est mon type de contrat:

[Serializable] 
public partial class TTLCContract 
{ 
    public virtual long? Id { get; set; } 
    // other properties here 
    public virtual Iesi.Collections.Generic.ISet<TTLCService> Services { get; set; } 

    // implementation of Equals 
    // and GetHashCode here 
} 

et ceci est mon type de service:

[Serializable] 
public partial class TTLCService 
{ 
    public virtual long? Id { get; set; } 
    // other properties here 
    public virtual Activity.Models.TTLCContract Contract { get; set; } 

    // implementation of Equals 
    // and GetHashCode here 
} 

Ok, donc comme vous pouvez le voir, je veux que mon objet du contrat pour avoir beaucoup services , et chaque service doit avoir une référence au contrat parent.

J'utilise FluentNhibernate. Donc, mon fichier de mappage sont les suivantes:

public TTLCContractMapping() 
{ 
    Table("tab_tlc_contracts"); 
    Id(x => x.Id, "tlc_contract_id"); 
    HasMany(x => x.Services) 
      .Inverse() 
      .Cascade.All() 
      .KeyColumn("tlc_contract_id") 
      .AsSet(); 
} 

et

public TTLCServiceMapping() 
{ 
    Table("tab_tlc_services"); 

    Id(x => x.Id, "tlc_service_id"); 
    References(x => x.Contract) 
     .Not.Nullable() 
     .Column("tlc_contract_id"); 
} 

et vient ici mon problème: si je récupère la liste de tous les contrats dans le db, cela fonctionne. si je récupère la liste de tous les services dans un contrat donné, je reçois une StackOverflowException ....

Voyez-vous quelque chose de mal avec ce que j'ai écrit? Ai-je commis une erreur?

S'il vous plaît laissez-moi savoir si vous avez besoin d'informations supplémentaires. Oh oui, j'ai raté de dire ... en regardant la pile, je vois que le système charge tous les services et ensuite il charge à nouveau les contrats liés à ces services.

Je n'ai plus vraiment l'expérience ni les idées nécessaires pour comprendre ce qui se passe ... donc toute aide serait vraiment super! Merci d'avance, Cheers,

+0

Avez-vous vraiment besoin de l'inverse ici? –

+0

Eh bien, c'est quelque chose que j'ai mis en place pour essayer de résoudre ce problème. Comme je l'ai dit, j'ai manqué d'idées:/Oh, aussi .. Je recevais une exception différente sans cela, donc je suppose que c'est nécessaire ... dans la table tab_services il y a une référence au contrat (donc, tab_tlc_services. tlc_contract_id), donc je pense que je pourrais être juste là .. mais comme je l'ai dit plus tôt, j'accepte les suggestions des experts ... –

+0

Pouvez-vous poster l'exception complète ('ex.ToString()')? –

Répondre

1

Il s'avère que les deux classes (TTLCContract & TTLCService) ont une fonction GetHashCode() personnalisée.

Eh bien, je me sens presque honte de poursuivre l'explication ...

GetHashCode de TTLCContract() appelai le GetHashCode de ses propres champs - et qui est juste. Bien que, l'un de ces champs était "Service", il y avait donc un appel tel que Service.GetHashCode(). Cette dernière fonction a été construite selon le même principe: elle appelait la fonction GetHashCode() sur chacun de ses champs internes. Et l'un d'eux est contrat. Ainsi, Contract.GetHashCode() appelait Service.GetHashCode() et Service.GetHashCode() appelait Contract.GetHashCode(). Cette boucle était la raison de l'exception StackOverflowException.En fait, la situation était un peu plus complexe que celle que je viens de décrire: Contrat et Service ont effectivement beaucoup d'objets enfants, et j'ai eu le même problème sur beaucoup d'entre eux.

Notre suite de tests a maintenant été réécrite pour tester ces éventualités.

0

Il semble que vous puissiez avoir une référence circulaire. par cela je veux dire que vous chargez les services qui inturn charge les contrats qui chargent alors les services et tour nous allons encore ...

Je ne suis pas sûr de la syntaxe nhibernate courante mais regardons au chargement paresseux des services et des contrats afin que vous n'obteniez pas cet effet en cascade.

+0

Les références et collections NHibernate sont paresseuses par défaut, et même si elles ne l'étaient pas, la carte d'identité garantit le fonctionnement des références circulaires. –

+1

Merci Diego pour la clarification. A-t-il toujours été le cas ou seulement récemment changé pour être paresseux par défaut? –