views:

123

answers:

2

Hi there!

In my project I am using NHibernate/FluentNHibernate, and I am working with two entities, contracts and services.

This is my contract type:

[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
}

and this is my service type:

[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, so as you can see, I want my contract object to have many services, and each Service needs to have a reference to the parent Contract.

I am using FluentNhibernate. So my mappings file are the following:

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();
}

and

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

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

and here comes my problem: if I retrieve the list of all contracts in the db, it works. if I retrieve the list of all services in a given contract, I get a StackOverflowException....

Do you see anything wrong with what I wrote? Have I made any mistake?

Please let me know if you need any additional information.

Oh yes, I missed to say... looking at the stacktrace I see the system is loading all the services and then it is loading again the contracts related to those services.

I don't really have the necessary experience nor ideas anymore to understand what's going on.. so any help would be really really great!

Thanks in advance, Cheers, Gianluca.

A: 

It looks as though you may have a circular reference happening. by that I mean you load the services which inturn loads the contracts which then load the services and round we go again...

I am not sure of the fluent nhibernate syntax but look in to lazy loading of both services and contracts so that you don't get this cascade effect.

Nathan Fisher
NHibernate references and collections are lazy by default, and even if they weren't, the identity map guarantees that circular references work.
Diego Mijelshon
Thanks Diego for the clarification. Has it always been the case or only recently changed to be lazy by default?
Nathan Fisher
A: 

It turns out that both the classes (TTLCContract & TTLCService) have a customized GetHashCode() function.

Well, I feel almost ashamed to carry on with the explanation...

TTLCContract's GetHashCode() was calling the GetHashCode of its own fields - and that's right. Although, one of these fields was "Service", hence there was a call such as Service.GetHashCode(). This latter function had been built following the same principle: it was calling the GetHashCode() function on each one of its internal fields. And one of these is Contract.

So, Contract.GetHashCode() was calling Service.GetHashCode() and Service.GetHashCode() was invoking Contract.GetHashCode(). This loop was the reason of the StackOverflowException.

Actually, the situation was kind of more complex than the one I have just described: Contract and Service have many child objects indeed, and I had the same problem on many of them.

Our test suite has now been rewritten to test against these eventualities too.

Gianluca Colucci