Crudler
Crudler

Reputation: 2286

fluent nhibernate circular reference pain

I have 2 objects in my domain A, and B

Object A has a property of B Object B has a property of list

when I do a hit on my db, of B, it returns a list of As, but each A has a B, which in turn has a list of As. over and over and over.

clearly a lazy loading issue. Lazy loading is on, but my problem is that this is a WCF service, do i need to convert all my domain objects into dto objects to send down the wire and when i do it does the following - pseudocode

ADTO adto Transform(ADomain a)
{
   adto.name = a.name;
   adto.surname = a.surname;
   adto.B = Transform(a.B);
}

BDTO bdto Transform(BDomain b)
{
   bdto.bob = b.bob;
   foreach (A a in b.As)
   {
       bdto.bs.add(Transform(a));
   }
}

so how can i make my fetch of the collection only go one layer deep.

B's mapping:

HasMany(x => x.As)
            .Cascade.AllDeleteOrphan()
            .Fetch.Select()
            .Inverse().KeyColumn("AId");

A's mapping:

 References(x => x.B).Column("AId");

Upvotes: 3

Views: 2226

Answers (1)

Radim Köhler
Radim Köhler

Reputation: 123861

Well, to pass circular reference over WCF you should adjust the Parent DTO (B) with IsReference parameter DataContractAttribute.IsReference Property (or here The Problem of Circular References).

Use the IsReference property to instruct the DataContractSerializer to insert XML constructs that preserve object reference information. [DataContract(Namespace = "http://domain.../", IsReference=true)] public class BDTO ...

To give you answer:

...so how can i make my fetch of the collection only go one layer deep.

NHibernate won't have any issue with circular references. And even more, you can easily get all the data while executing 2 SQL queries only. Adjust the mapping:

HasMany(x => x.As)
  .Cascade.AllDeleteOrphan()
  .BatchSize(25)
  //.Not.LazyLoad()
  .Inverse()
  .KeyColumn("AId");

NOTE: Not.LazyLoad make sense only if the A object is almost always needed to get B working. When "lazy" mode is used, you have to keep the session opened during the whole WCF service processing

The BatchSize setting will optimize loading lists of B objects. Read more here: http://ayende.com/blog/3943/nhibernate-mapping-set

NHibernate session will execute two queries 1) Select B and 2) Select A for all B and materialize the results into complete A and B instances, with both-ways references fully populated. The NHibernate session will serve you fully loaded instances. Even calls Get<A>(id) and Get<B>(id) will retrieve the objects from session

Next steps are up to you, you can use DTO objects, mapping tools to convert them...

Upvotes: 1

Related Questions