Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop lazy loading or skip loading a property in NHibernate? Proxy cannot be serialized through WCF

Consider I have a parent, child relationship class and mapping. I am using NHibernate to read the object from the database, and intended to use WCF to send the object across the wire.

Goal

  • For reading the parent object, I want to selectively, at different execution path, decide when I would want to load the child object. Because I don't want to read more than what I needed.
  • Those partially loaded object must be able to sent through WCF. When I mean I don't load it, neither side will access such property.

Problem

  • When such partially loaded object is being sent through WCF, as those property is marked as [DataContract], it cannot be serialized as the property is lazy load proxy instead of real known type.

What I want to archive, or solution that I can think of

  • lazy=false or lazy=true doesn't work. Former will eagerly fetch all the relationships, latter will create a proxy. But I want nothing instead - a null would be the best.
  • I don't need lazy load. I hope to get a null for those references that I don't want to fetch. A null, but not just a proxy. This will makes WCF happy, and waste less time to have a lazy-load proxy constructed.
    Like could I have a null proxy factory?
    -OR-
  • Or making WCF ignoring those property that's a proxy instead of real. I tried the IDataContractSurrogate solution, but only parent is passed to GetObjectToSerialize, I never observe an proxy being passed through GetObjectToSerialize, leaving no chance to un-proxy it.

Edit

After reading the comments, more surfing on the Internet...

It seems to me that DTO would shift major part of the computation to the server side. But for the project I am working on, 50% of time the client is "smarter" than the server and the server is more like a data store with validation and verification. Though I agree the server is not exactly dumb - I have to decide when to fetch the extra references already, and DTO will make this very explicit.

Maybe I should just take the pain. I didn't know http://automapper.codeplex.com/ before, this motivates me a little more to take the pain.

On the other hand, I found http://trentacular.com/2009/08/how-to-use-nhibernate-lazy-initializing-proxies-with-web-services-or-wcf/, which seems to be working with IDataContractSurrogate.GetObjectToSerialize.

like image 983
HelloSam Avatar asked Mar 07 '10 17:03

HelloSam


2 Answers

Was getting the same issue with WCF-Silverlight transferring of DTO/Entities. I use following code which works fine:

Fluent NHibernate:

References(c => c.DataSource)
    .Column("DataSourceId")
    .Cascade.None()
    .Not.LazyLoad();
HasManyToMany(c => c.Categories)
    .Table("Categories")
    .ParentKeyColumn("ItemId")
    .ChildKeyColumn("CategoryId")
    .Not.LazyLoad()
    .Cascade.None()
    .Inverse();

XML:

<many-to-one name="DataSource" column="DataSourceId" lazy="false" cascade="none" />

Hope this'll work for you!

like image 104
Andrey S Avatar answered Nov 14 '22 18:11

Andrey S


I have run into similar issues with performance, what I did instead was preload the information I want by using an explicit call to the DB using a DetachedCriteria.

So similar to what you are doing I would probably do something like this.

public DetachedCriteria BuildMyCriteria()
{
    var criteria = DetachedCriteria.For<ParentClass>();
    criteria.CreateCriteria("this.ChildClass", "Child Class").SetFetchMode("this.ChildClass", FetchMode.Eager);
    criteria.Add(Restrictions.IsNotNull("ChildClass.Property");      

    return criteria;
}

Then from my facade, I would get those entities with the properties that do not have null attributes on the child property

var myClasses = _repository.ExecuteDetachedCriteria<ParentClass>(BuildMyCriteria);

Then I would have all ParentClass entities that have a null property.

So instead of taking a hit by constantly asking the DB for info, I store it in memory so it is ready for me to use.

This is just an alternative solution to DTOs, good luck :)

like image 43
Timbob Avatar answered Nov 14 '22 19:11

Timbob