0

Recently i had some performance problems in a SOAP webservice I wrote a while ago. I noticed I had a lot of queries going on and my hbm.xml mappings where full of lazy=false statements. I upgraded to NHibernate 3.0 and removed the lazy = false stuff and everything was a LOT faster....but now i am getting the following error:

System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type UserProxy was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

User is a class of which i removed the lazy=false property from the class tag like this:

<class name="User" table="Users" >
  <id name="DatabaseID" unsaved-value="0" column="ID" type="integer" >
    <generator class="native"/>
   </id>
   <property name="IsExpert"/>
    .....more stuff here....
</class>

My webservice has a method like this (simplified a little..in real-life i use a repository-like pattern between the service and nhibernate):

    [WebMethod]
    public User GetUser(int userid)
    {
        session = GetCurrentSession();
        return session.Load<User>(userid);                         
    }

The webservice expects to serialize a user and NHibernate gives me a UserProxy (which is not a user exactly). How should I overcome this?

Gluip
  • 2,917
  • 4
  • 37
  • 46
  • It seems this question is related. Here it is suggested to use different classes for NHibernate and the webservice (DTO)..http://stackoverflow.com/questions/2641673/nhibernate-wcf-bidirectional-and-lazy-loading – Gluip Jul 30 '11 at 11:45

2 Answers2

2

Don't return entities from the web method. Use a DTO.

Diego Mijelshon
  • 52,548
  • 16
  • 116
  • 154
  • I don't like the plumbing. Maybe if ill have more problems. For now I just turned off lazy and did some other tweaks. – Gluip Jul 30 '11 at 16:37
  • @Gluip: you've just deferred the problem (and created a different set of issues). It will get bigger. – Diego Mijelshon Jul 30 '11 at 16:44
  • For the last 4 years it wasn't a problem...if I find the time to really address it I guess I'll look into separate DTO's. Seems like I have to represent each class 3 times :( – Gluip Jul 30 '11 at 18:26
  • another answer pointing int the DTO direction....http://stackoverflow.com/questions/1190718/how-do-i-serialize-all-properties-of-an-nhibernate-mapped-object – Gluip Jul 30 '11 at 18:29
  • @Gluip: if your DTOs are exactly the same as your entities, your service is just a SQL proxy. Maybe you should review how your service interactions are designed. – Diego Mijelshon Jul 30 '11 at 22:21
  • Gluip: don't make a problem out of it. Copy classes, decorate with [Serialize] and use AutoMapper. 1 hour and you're done. Application will be faster and you will gain one level up in Good Design. – IamDeveloper Jul 31 '11 at 19:34
  • I will probably make a copy of the objects i want to return so i get the stuff I really need and can use lazy. I probably will use the same classes for DTO though I might chose custom classes. I agree it is not a big problem, but was wandering if there is nicer way than copying the whole object (recursivily) into another object. My service is not just a SQL proxy because there is more business logic in there and i want to 'hide' the db from the clients – Gluip Aug 02 '11 at 13:49
0

Webservices cannot serialise proxies - session.Load(userId) will return a proxy. You should user session.Get(userId) .

I think the answers saying you should use DTOs are not helpful, there is a time and place for DTOs and sometimes you may just want to return the entity.

If the User has child proxy properties, I have a class for handling this situation. Basically it loops through all properties (using reflection, and recursively going through child objects and collections) and uses the NHibernate.IsInitialized to check whether the property is a proxy or the genuine article. If it is a proxy then it sets it to null, thus making it possible for WCF to serialise it.

Paul T Davies
  • 2,527
  • 2
  • 22
  • 39