Friday, January 12, 2007

Lazy Loading in a SOA world.

As a "side effect" of my current project, I am helping my client build a SOA interface to another large system. This client has traditionally used datasets for most of their data access, and one of my goals is to get the harsh dataset monkey off their backs and wean them onto the smooth, mellow high of business domain objects. After all, all the really cool Enterprises are doing it! I'm also trying to champion the "One interface to rule them all" cause, so this (eventually) will be the ONE and ONLY way to get data from, or put data in this system.

In putting together a proof of concept, I came across a bit of a problem; my entity has several properties that return lists of items. Some of these lists can be quite large, so we want to lazy load them. For my example, I created a person, who had a list of four address (I’m just returning four hard-coded ones since I didn’t want to muck with the database for the proof of concept) which I wanted to lazy load. I wired everything up and it was working beautifully!

Except for one thing; I was getting eight addresses back.

Here’s the problem; when the web service was getting ready to send my person object back, it was serialized by the XML serializer. That serializer was looking at my address property, which caused a lazy load. So, my object was initially coming over the wire with all the lists populated. One the client side, the de-serialization was also calling the address property, which was again lazy loading the address right away. I had a check in the “get” to make sure the list was null before the loading occurred, so how BOTH lists got merged together is something I can only wildly speculate about at this point, but it was merely a side effect of a different problem, so I didn’t worry about it.

The solution was to find a way for the XML Serializer to ignore that property when it was sending it out.

The solution: the XMLIgnore attribute. Decorating my property with this attribute causes the serializer to skip it. It doesn’t get looked at during serialization, it’s ignored during de-serialization and my lazy load routine work beautifully.

And all was well in the kingdom of SOA (for now…)

4 comments:

Anonymous said...

Nice post. I have to be honest and say that I did not know you could turn serialization on/off on various attributes like this but I can certainly think of a bazillion situations where it would need to be done.

agovorine@gmail.com said...

or you can solve this problem by de-coupling your object into: entity business object and data transfer object. You will control what dto sends over the wire.
There are plenty of tools that can do it for you, like Software Factory :)

James Bender said...

Alexey: You make a good point, and we are using Service Factory for this project. Service Factory, out of the box, does this decoupling for you, and I agree this is the way to go, in general.

A lot of people who are new to Service Factory, and to SOA best practices in general, are a little taken aback by the number of projects that Service Factory creates, and Service Factory does provide a mechanism to reassign project responsiblity as a means to consolidate projects in your solution a little. Generally, I'm not a fan of consolidating Business Entities and Data Types, but most users seem to point to that first as a place to do this. I have found that instead of giving them the 100's of reason why they shouldn't, let them work through a POC, on their own, with that consolidation. It doesn't take long for them to come back around to my way of thinking.

Sometimes, you just have to touch the stove. :)

In this case, all of our stuff is happening in one big federated family, so I was willing to open my mind to the idea a little, since with no truly public interface, and several months before we need to actually utilize this, the risk was on the low side.

Anonymous said...

Would you use this technique on singular dependent properties if you have a large object graph? If so, if you XMLIgnore a property, how does your getter know what to get? In other words do you have a property that holds a constraint? I.e. the ID of the dependent object?