NHibernate and WCF is Not a Perfect Match

From the last days of playing around with and learning NHibernate it's quite clear to me that NHibernate is not a perfect match for a WCF solution. I'm perfectly aware of the fact that I'm still a total NH newbie, so please correct me or help me out if you can.

From the moment I heard of Hibernate years ago I thought it was best made for stateful solutions and not web apps or web services, and from what I can see that is still the case. I like many of the things I see in NH, especially the way you can map existing and bad looking databases to better looking domain entities, and the work on NHibernate Fluent looks promising.

You have to understand how lazy loading does (not) work with web services and serializing problems you may run into. But I think the biggest problem lies in the session management of NHibernate and where to open and close your NHibernate session. I won't even go into the different options proposed by hundreds of bloggers, just Google it. The thing is I don't want to be dependant on more 3rd party or open source components than necessary - it can easily get out of control.

I still want to use NHibernate for our WCF project because I do think can help us map the old, existing database we have to work with to decent domain entities, but I'm afraid we will run into weird problems later on. This approach seems to be one of the best so far, but I need to test it out some more and I'm not sure it will handle lazy loaded/HasMany data. Quite a few projects have run into problems with the session being closed before the serialization of lazy loaded objects happens :/

We may have to use EF instead.

7 Comments

  • Remoting entities is generally a bad idea (remember EJB?). Entities should not cross context boundaries (i.e. web services, remoting, etc).

    You can also turn off lazy-loading. But again, all these are smells pointed towards the larger problem which is "remoting entities across context boundaries."

    I strongly urge you NOT to do this as this is only the tip of the iceberg of problems you will face with this approach.

    I can also pretty much guarantee you that moving to EF is NOT going to make your problems any easier (quite the contrary).

  • I have to agree with Chad. It seems you have a design problem somewhere rather than an NH problem.

  • I use NH in WCF with a fair degree of ease. Set this as your data contract surrogate. Just left/inner join in relations that you want to send across the pipe.

    public class NhDataContractSurrogate : IDataContractSurrogate {

    #region IDataContractSurrogate Members
    public object GetObjectToSerialize(object obj, Type targetType) {
    INHibernateProxy proxy = obj as INHibernateProxy;
    if (proxy != null) {
    ILazyInitializer li = proxy.HibernateLazyInitializer;
    obj = (li.IsUninitialized ? null : li.GetImplementation());
    }
    return obj;
    }

    public object GetCustomDataToExport(Type clrType, Type dataContractType) {
    return null;
    }

    public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) {
    return null;
    }

    public Type GetDataContractType(Type type) {
    return type;
    }

    public object GetDeserializedObject(object obj, Type targetType) {
    return obj;
    }

    public void GetKnownCustomDataTypes(Collection customDataTypes) {
    }


    public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) {
    return null;
    }

    public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) {
    return typeDeclaration;
    }

    #endregion
    }

  • @Chad - Yes, I do remember EJB, but I'm not doing remoting here. This is stateless and I usually map internal entities to data contracts that go on the wire. I'm just trying things out here and thought that just maybe I could use NH's great mapping features to create entities that *could* go on the wire when dealing with simpler services.

    I tried to turn off lazy loading, but it seems that I ran into an issue/fault in the latest NHibernate Fluent release according to people on the Google group for Fluent. So typical me.

    Would be interesting to hear why EF would make things harder for me.

  • @Allan - Thanks for the tip on using IDataContractSurrogat. I'll look at it! I saw some people using NetDataContractSerializer, but that's not an option for me.

  • NHibernate's ORM mapping shouldn't be used in the message that you use for wire transfers. You should build your messages with the data from NHibernate's serialization classes that you've created.

    NHibernate's sessions are lightweight and you should create and release in as short statements as possible (smallest possible transactions). A lot of developers use some kind of unit of work pattern.

    Only thing to care about is that you should just create the factory once.

  • @Ramon - As I wrote to Chad, we're normally not/never exposing internal entities from a service on the wire like this, this was something we did now when trying out NH with WCF.

    What we will do next is to set up a proper solution for a Unit of Work were the session is opened and closed and map NH entities to WCF data contracts to be sent on the wire.

    Thanks for the concerns about the creation of the factory. We're using Unity as our container and the factory is created only once as a singleton and that part seems to work just fine. Just have to figure out the best possible way to create and close the session :)

Comments have been disabled for this content.